When you install Visual Studio 2008, you automatically get an updated version of the Windows Mobile Device Emulator (version 3) and Device Emulator Manager. As you may know, the new Device Emulator Manager exposes a programmable interface; the programmable interface allows you to write desktop computer applications that can programmatically access all of the interactive features of the Device Emulator Manager. These features include connecting an emulator, cradling an emulator, resetting the emulator, and so on.
The emulator features are intuitive and easy to use; basically each of the emulator functions corresponds directly to a Device Emulator Manager menu options. The one thing that is a bit of a challenge is getting access to a specific emulator.
The Device Emulator Manager organizes the emulators hierarchically: the Device Emulator Manager contains Categories which contain SDKs which contain Emulators. To reach an emulator you have to loop through the levels above it; there's no way to access an emulator directly.
What makes reaching a specific emulator a minor challenge is that the Device Emulator Manager API does not provide standard enumerators over the collections representing each level of the hierarchy. Another factor is that the API is implemented as COM Automation interfaces and uses COM HRESULTS (error codes) to indicate status changes such as end-of-data.
When using the API from .NET, the .NET interoperability layer interprets these non-zero HRESULTS as errors and translates them into COMExceptions. As a result, when looping through a collection, you have to catch a COMException to handle the end-of data. Similarly, the API indicates an empty collection by throwing a COMException when you attempt to access the first member of the collection. So your looping code ends up looking a bit verbose because of the layers of try/catch required.
The solution is to have a FindEmulator function that encapsulates all of these details so that you can easily get right to the emulator of interest.
My goal is to have a utility that allows you to work with the emulators using code like the following...
// Would generally be declared at the class level
IDeviceEmulatorManager _demManager;
DEMUtility _demUtility;
// Create once
_demManager = new DeviceEmulatorManagerClass();
_demUtility = new DEMUtility(_demManager);
// Now can just search for emulators by name
IDeviceEmulatorManagerVMID theEmulator = _demUtility.FindEmulator("Windows Mobile 5.0 Pocket PC Emulator");
if (theEmulator != null)
{
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
}
I've written a simple DEMUtility class that supports using the emulators as shown above.
You basically create an instance of the DEMUtility class passing a reference to a IDeviceEmualtorManager (top-level interface of the DEM Automation API). Once you've done that you can search for individual emulators by calling the DEMUtility class' FindEmulator function and passing the emulator's display name (name that appears in the Device Emulator Manager's interactive display). Each emulator is also identified by a GUID called a VMID. If you know the VMID for a particular emulator, you can pass the VMID to FindEmulator in place of the name.
Here's the implementation of the DEMUtility class
class DEMUtility
{
const int END_OF_DATA = -2147024637;
const int E_ENUMSDK_NOT_LOADED = -2147209216;
const int E_ENUMSDK_INVALID_ENUMVMID = -2147209215;
const int E_ENUMVMID_NOT_LOADED = -2147209214;
const int E_ENUMVMID_INVALID_VMID = -2147209213;
IDeviceEmulatorManager _emulatorManager;
public DEMUtility(IDeviceEmulatorManager emulatorManager)
{
if (emulatorManager == null)
throw new ArgumentException("Must provide a valid IDeviceEmulatorManager Reference", "emulatorManager");
_emulatorManager = emulatorManager;
}
public IDeviceEmulatorManagerVMID FindEmulator(string nameOrVmid)
{
string categoryName;
string sdkName;
string emulatorName;
string emulatorVMID;
if (string.IsNullOrEmpty(nameOrVmid))
throw new ArgumentException("Must provide a non-null, non-empty emulator name or VMID", "nameOrVmid");
try
{
_emulatorManager.Reset();
while (true)
{
categoryName = _emulatorManager.get_Name();
IEnumManagerSDKs sdkEnum = _emulatorManager.EnumerateSDKs();
sdkEnum.Reset();
try
{
while (true)
{
try
{
sdkName = sdkEnum.get_Name();
IEnumVMIDs vmidEnum = sdkEnum.EnumerateVMIDs();
vmidEnum.Reset();
try
{
while (true)
{
try
{
IDeviceEmulatorManagerVMID tempEmulator = vmidEnum.GetVMID();
emulatorName = tempEmulator.get_Name();
emulatorVMID = tempEmulator.get_VMID();
if (emulatorName == nameOrVmid ||
emulatorVMID == nameOrVmid)
return tempEmulator; // If name or VMID matches, return
}
catch (COMException ex)
{
// Indicates no emulator
if (ex.ErrorCode == E_ENUMVMID_INVALID_VMID ||
ex.ErrorCode == E_ENUMVMID_NOT_LOADED)
break;
else
throw ex;
}
vmidEnum.MoveNext();
}
}
catch (COMException ex)
{
// End of data
if (ex.ErrorCode != END_OF_DATA)
throw ex;
}
}
catch (COMException ex)
{
// Indicates empty SDK
if (ex.ErrorCode == E_ENUMSDK_NOT_LOADED)
break;
else
throw ex;
}
sdkEnum.MoveNext();
}
}
catch (COMException ex)
{
// End of data
if (ex.ErrorCode != END_OF_DATA)
throw ex;
}
_emulatorManager.MoveNext();
}
}
catch (COMException ex)
{
// API signals end-of-data with a No More Data HResult.
if (ex.ErrorCode != END_OF_DATA)
throw ex;
}
return null; // No match found
}
}
I know the FindEmulator function looks a bit unusual but that's due to needing to handle the various COMExceptions along the way. There's really no simpler way to loop through the DEM hierarchy.
To use the Device Emulator Manager automation features or the DEMUtility class you need to add a reference to %Program Files%\Microsoft Device Emulator\1.0\Microsoft.DeviceEmulatorManager.Interop.9.0.dll using the "Browse" tab on the Add Reference dialog. You also need to add using statements (imports for VB) to the Microsoft.DeviceEmulatorManager.Interop and System.Runtime.InteropServices namespaces.
A "How Do I?" video and a MSDN paper on using the Device Emulator Manager automation features will be available shortly.
BTW: If anyone needs the DEMUtility class source code in Visual Basic .NET, let me know via feedback to this blog entry and I'll post that version of the code as well.
As always, questions are welcome.
Posted
Oct 30 2007, 08:45 AM
by
jim-wilson