How To: Programmatically Control the Windows Mobile Device Emulators from .NET

4/7/2010

Jim Wilson, JW Hedgehog, Inc.

November 2007

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.

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

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.

Bb936678.note(en-us,MSDN.10).gifNote:
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 is implemented as a Component Object Model (COM) In-Process Library. The .NET assembly file Microsoft.DeviceEmulatorManager.Interop.9.0.dll provides 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 COMExceptions when working with the API.

Bb936678.note(en-us,MSDN.10).gifNote:
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.0 assembly. 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.dll assembly 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 COMExceptions that API may throw.

Bb936678.note(en-us,MSDN.10).gifNote:
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 IDeviceEmulatorManagerVMID interface. The IDeviceEmulatorManagerVMID interface 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 IDeviceEmulatorManagerVMID interface, you can programmatically perform the actions exposed by the Device Emulator Manager user interface. Table 1 shows the IDeviceEmulatorManagerVMID interface 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_STATE enumeration 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).

Bb936678.note(en-us,MSDN.10).gifNote:
The GetConfiguration and SetConfiguration methods 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 IDeviceEmulatorManagerVMID interface.

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_State method 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 Connect method. 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 Cradle method; 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 BringToFront method.

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.

Bb936678.note(en-us,MSDN.10).gifNote:
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 Wrapper section, 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 DeviceEmulatorManagerClass class. This class encapsulates the COM component that represents the Device Emulator Manager. When working with the Device Emulator Manager, you can use the DeviceEmulatorManagerClass class directly or use the IDeviceEmulatorManager interface. 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.

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 IDeviceEmulatorManager interface and the way the IDeviceEmulatorManager interface indicates the end of the list. First, the multifaceted nature of the IDeviceEmulatorManager interface. The IDeviceEmulatorManager interface 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.MoveNext method indicates that there are no more categories left, which is to throw a COMException. The following sample demonstrates aspects of both points.

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 IDeviceEmulatorManager interface represents multiple roles. You can see in the preceding sample code that the IDeviceEmulatorManager reference, emulatorManager, exposes the methods Reset, MoveNext, and get_Name. The first two methods allow you to work with the category enumerator. The Reset method positions the emulatorManager reference at the beginning of the category list; the MoveNext method advances the emulatorManager reference to the next category in the list. The get_Name method 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 IDeviceEmulatorManager methods that represent the Device Emulator Manager role, however upcoming code samples will. Similar multi-role behavior is repeated in the IEnumManagerSDKs interface discussed in the next section.

With regard to the way that the MoveNext method indicates that no categories remain, notice that the loop iterating over the category list uses a true value as the exit condition for the while loop. Using a true value within the loop condition often indicates an endless loop, but not in this case. As you can see, the while loop is contained within the try portion of a try/catch block. The way this code is written, the only way to exit the while loop is for one of the Device Emulator Manager API methods to throw an exception. In fact, that is how the MoveNext method 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 MoveNext method, this is exactly what happens.

When the call to the MoveNext method causes the emulatorManager to advance beyond the end of the category list, the MoveNext method 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 COMException when reaching the end of the category list; the preceding code catches the exception outside of the while loop and checks the COMException HRESULT. When the HRESULT is the expected end-of-data value the program continues normally, otherwise the COMException is 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 IEnumManagerSDKs interface. You access the SDK enumerator for a specific category through the IDeviceEmulatorManager.EnumerateSDKs method for that category. Similar to the IDeviceEmulatorManager interface, the IEnumManagerSDKs interface 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 ListDEMCategoryMembers method shown in the previous sample 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 COMException with an HRESULT value of -2147024637. In addition to the catch block 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 Reset method positions the enumerator at the first item in the list and you cannot call the MoveNext method until you no longer need the first list item, because the call to the MoveNext method 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_Name method. When you call the get_Name method 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 COMException containing this same HRESULT. Like when reaching the end of the list, the program catches the COMException and checks that the HRESULT has the expected value, if not, the COMException is re-thrown.

Working with the Emulator List

The IEnumVMIDs interface 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 ListDEMSdkMembers method shown in the previous sample 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_VMID in some cases and DeviceEmulatorManagerErrorCodes.E_ENUMVMID_NOT_LOADED in others. For this reason, the catch block must check for both of these HRESULTs in addition to the end-of-data HRESULT.

Unlike the IDeviceEmulatorManager and IEnumManagerSDKs interfaces, which each represent both their list enumerator and the current item in their list, the IEnumVMIDs interface represents only the Device Emulator list enumerator. To access an individual Device Emulator enumerator, you use the IDeviceEmulatorManagerVMID interface. 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 Emulator section 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 Find method. To create a Find method 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 Find method 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.RegisterRefreshEvent method. 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.

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 RefreshEventMonitor method. This method runs on a thread separate from the main application. Anytime the synchronization event signals, RefreshEventMonitor performs the appropriate action to deal with the Device Emulator Manager hierarchy changes. Each instance of the DeviceEmulatorManagerClass and the related Device Emulator Manager classes cache the list of objects in the Device Emulator Manager hierarchy; therefore, most applications should call the IDeviceEmulatorManager.Refresh method 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 RefreshEventMonitor method then goes back to monitoring for changes.

Bb936678.note(en-us,MSDN.10).gifNote:
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.Refresh method 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 RefreshEventMonitor continues monitoring for changes until the class-level field, _shutDownRequested, is set to true. Notice that the _shutDownRequested field is declared with the volatile keyword; this is necessary because the thread that modifies the field value is separate from the thread that reads the field value. Without the volatile modifier, the thread monitoring for refresh events may cache the value of the _shutDownRequested field, 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 SetupEventListener method. This method starts by creating a named Win32 synchronization AutoReset event object. As an AutoReset synchronization event, the synchronization event guarantees that the RefreshEventMonitor method will carry out exactly one iteration of the while loop; the next time the RefreshEventFunction calls the _refreshEvent.WaitOne method, 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.

Bb936678.note(en-us,MSDN.10).gifNote:
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 RefreshEventMonitor method 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 ShutdownEventListener method takes care of the details. The ShutdownEventListener method first calls the IDeviceEmulatorManager.UnRegisterRefreshEvent method to inform the Device Emulator Manager API that the program no longer needs to be notified of changes. The method then shuts down the RefreshEventMontor thread and releases the synchronization event.

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 IDeviceEmulatorManager interface 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 IDeviceEmulatorManager interface.

DeviceEmulatorCategory

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

DeviceEmulatorSdk

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

DeviceEmulator

Represents an individual Device Emulator. Provides the same features as the IDeviceEmulatorManagerVMID interface.

With the exception of the DeviceEmulator class, the classes in Table 2 are relatively simple. In general they expose a Name property 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 IDeviceEmulatorManager interface.

DeviceEmulatorSdkCollection

Represents a list of SDKs. Encapsulates the enumeration features of the IEnumManagerSDKs interface.

DeviceEmulatorCollection

Represents a list of Device Emulators. Encapsulates enumeration features of the IEnumVMIDs interface.

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.

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.

Bb936678.note(en-us,MSDN.10).gifNote:
Each of the samples in this section and the following section makes the assumption that there is an existing DeviceEmulatorManagerEx variable named demManagerEx.

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

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.

Bb936678.note(en-us,MSDN.10).gifNote:
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.

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

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

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.

DeviceEmulator wm6Pro = 
  demManager.Categories["DataStore"].Sdks["Windows Mobile 6 Professional SDK"].DeviceEmulators["Windows Mobile 6 Professional Emulator"];
Bb936678.note(en-us,MSDN.10).gifNote:
In the case of locating a specific emulator, one would generally use the DeviceEmulatorManagerEx.FindEmulator method rather than a sequence of indexers.

Monitoring for Changes with the Device Emulator Manager Wrapper

The DeviceEmulatorManagerEx class makes Device Emulator Manager hierarchy change notifications available as a standard .NET event through the RefreshRequired event. The event type is MethodInvoker and 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 DeviceEmulatorManagerEx class.

The DeviceEmulatorManagerEx class 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.Invoke or Control.BeginInvoke.

Bb936678.note(en-us,MSDN.10).gifNote:
You should always call the Dispose method on the DeviceEmulatorManagerEx class. The Dispose method handles the details of terminating the thread that monitors for Device Emulator Manager hierarchy changes. If you forget to call the Dispose method, you may find that your application appears to stop responding during the application exit process.

Like the IDeviceEmulatorManager interface, the DeviceEmulatorManagerEx class includes a Refresh method to update the internal cache of Device Emulator Manager objects and hierarchies. Because the DeviceEmulatorManagerEx.RefreshRequired event signals your event handler on a thread separate from the main application thread, calling the Refresh method from your RefreshRequired event handler requires the same caution as described in the earlier IDeviceEmulatorManager.Refresh discussion.

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.

Show: