Last post we looked at how to write a device side agent. I am uploading the source for file viewer written using CoreCon API's.
How to use
- You need to have visual studio 2008 installed in your machine.
- Extract the zip file. It has 2 solutions and 2 xsl files.
- Take a back up of your global datastore directory
- In vista this is "C:\Users\All Users\Microsoft\corecon\1.0"
- In non-vista this is "c:\documents and settings\All users\Application Data\Microsoft\corecon\1.0"
- Copy the xsl files to "addons" directory inside the Global datastore directory.
- Build the solutions. Copy the RemoteAgent.exe to d:\temp\Armv4i directory. If you are keeping the file in different directory then you need to modify the RemoteAgent.xsl file accordingly (modify the RootPath property)
- Execute the FileViewer.exe - you have the fileviewer ready.
I have created the RemoteAgent.xsl package for Armv4i architecture only. If you want to work in any other architecture then you need to build the RemoteAgen.sln in the required architecture. Add a Packagetype entry in the Remoteagent.xsl for that architecture. In case you want to add support for X86, then add the following inside the Packagetypecontainer (in RemoteAgent.xsl)
<PACKAGETYPE Name="x86" ID="x86" Protected="True">
<PROPERTYCONTAINER>
<PROPERTY ID="RemotePath" Protected="True">%CSIDL_WINDOWS%</PROPERTY>
<PROPERTY ID="RootPath" Protected="True">D:\temp\x86</PROPERTY>
<PROPERTY ID="CommandLine" Protected="True"></PROPERTY>
<PROPERTY ID="CPU" Protected="True">x86</PROPERTY>
<PROPERTY ID="Host" Protected="True">RemoteAgent.exe</PROPERTY>
</PROPERTYCONTAINER>
<FILECONTAINER>
<FILE ID="RemoteAgent.exe" />
</FILECONTAINER>
</PACKAGETYPE>
Place the remoteagent.exe built for X86 in D:\temp\X86 directory.
--
Anand R
Attachment(s): fileviewer.zip
In the last post we saw how to create a package and use that for downloading set of files.
Writing Device Agent
What do I get if I write an my own agent?
- You can reliably start your agent. When the start call is completed you are guaranteed that your agent has started running in device.
- You can create stream independent of the underlying transport mechanism. You need not worry about whether DMA or TCP is the underlying transport.
- You can use the streams for your device-desktop interaction
- You need not worry about serializing and de-serializing the data you send.
- We provide a packet class which could be used to send and receive most of the basic data types.
Let’s see how we can write a device agent.
When an agent is started in device, it should call ‘AcknowledgeLaunch’.
Calling AcknowledgeLaunch signifies 2 things.
- Agent conveys that it has done with all its initialization and ready to accept connections from desktop
- It also registers the set of Ids that will be used to create streams.
Here is the code snippet to do AcknowledgeLaunch
HRESULT (*pfnGetDeviceService)(IDeviceAgentTransport**);
hMod = ::LoadLibrary(L "DeviceAgentTransport.dll");
if(hMod == NULL)
{
//Error Handle…
}
pfnGetDeviceService = (GetDeviceAgentTransportFunction) ::GetProcAddress(hMod,L"GetDeviceAgentTransport");
if( NULL == pfnGetDeviceService)
{
//Error Handle…
}
hr = pfnGetDeviceService(out_pTransport);
if(FAILED(hr))
{
//Error Handle…
}
//We got the DeviceAgentTransport. Call acknowledgelaunch to indicate all initializations are done.
hr = out_pService->AcknowledgeLaunch(count,lpServiceIds);
if(FAILED(hr))
{
//Error Handle…
}
Now, the Device agent is ready to accept connections…
IDevicePacketStream* out_pStream;
out_pService ->AcceptConnectionEx(lpServiceId ,&out_pStream);
AcceptConnectionEx is analogous to TCP accept call. This is a blocking call and will wait till a Connect (CreatePackaetStream) call is made from desktop with the same serviced. Note that this serviced has to be one among the registered service Ids (in AcknowledgeLaunch).
Send receive Packets
Let’s send some packets to desktop.
We need to create a packet, write the info into the packet and send the packet in stream.
GetNewPacketFunc packFunc;
HINSTANCE hMod = ::LoadLibrary(L "DeviceAgentTransport.dll");
packFunc = (GetNewPacketFunc) ::GetProcAddress(hMod, L"GetNewPacket");
if( NULL == packFunc)
{
//Error Handle…
}
IPacket *writePacket;
packFunc(&writePacket);
writePacket->WriteString(szSendString); //Some string to be sent to desktop
out_pStream->write(writePacket);
Just like in TCP, Read is a blocking call. Below call will wait till some data is sent from the desktop.
IPacket *packet;
packFunc (&packet);
hr =out_pStream->Read(&packet);
Desktop Side
So far we are discussing about how the device agent will look like. We will look at the desktop counterpart for this.
//PackageId is the Guid corresponding to the package we want to deploy
RemoteAgent mRemoteAgent = Device.GetRemoteAgent(new ObjectId(packageID));
//This will start the agent. This call will be blocked till AcknowledgeLaunch is called in device side.
mRemoteAgent.Start(“”);
//This is the connect call.
//This will unblock the AcceptConnectionExe in device
DevicePAcketStream mStream = mRemoteAgent.CreatePacketStream(streamId);
Packet pkt = new Packet();
Pkt.WriteString(“hai”);
mStream.write(pkt);
pkt = mStream.Read();
string msg = pkt.ReadString();
Below is the sequence diagram for the desktop and device interaction
In next post we will look at actual File Viewer written using CoreCon API's.
--
Anand R
Package
More than often we would like to deploy multiple files as part of our application. Also these files might vary depending on the architecture of the device. To handle these CoreCon provides something called packages. Packages files are present in the datastore (e.g Microsoft.RemoteTools.Packages.xsl).
Let’s Look at a sample package(FileListPackage.xsl) which we can use for our FileList utility.
<?xml version="1.0" standalone="no"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<ADDONCONTAINER>
<ADDON>
<PACKAGECONTAINER>
<PACKAGE ID="0695ABA4-6A85-484d-8C07-5E67FE44D6BC" NAME="FileList">
<PACKAGETYPECONTAINER>
<PACKAGETYPE Name="ARMV4" ID="ARMV4" Protected="true">
<PROPERTYCONTAINER>
<PROPERTY ID="RemotePath" Protected="true">%CSIDL_PROGRAM_FILES%</PROPERTY>
<PROPERTY ID="RootPath" Protected="true">%CSIDL_PROGRAM_FILES%\MyUtility\ARMV4</PROPERTY>
<PROPERTY ID="CommandLine" Protected="true"/>
<PROPERTY ID="CPU" Protected="true">ARMV4</PROPERTY>
</PROPERTYCONTAINER>
<FILECONTAINER>
<FILE ID="FileList.exe"/>
</FILECONTAINER>
</PACKAGETYPE>
<PACKAGETYPE Name="ARMV4I" ID="ARMV4I" Protected="true">
<PROPERTYCONTAINER>
<PROPERTY ID="RemotePath" Protected="true">%CSIDL_PROGRAM_FILES%</PROPERTY>
<PROPERTY ID="RootPath" Protected="true">%CSIDL_PROGRAM_FILES%\MyUtility\ARMV4I</PROPERTY>
<PROPERTY ID="CommandLine" Protected="true"/>
<PROPERTY ID="CPU" Protected="true">ARMV4I</PROPERTY>
</PROPERTYCONTAINER>
<FILECONTAINER>
<FILE ID="FileList.exe"/>
</FILECONTAINER>
</PACKAGETYPE>
<PACKAGETYPE Name="X86" ID="X86" Protected="true">
<PROPERTYCONTAINER>
<PROPERTY ID="RemotePath" Protected="true">%CSIDL_PROGRAM_FILES%</PROPERTY>
<PROPERTY ID="RootPath" Protected="true">%CSIDL_PROGRAM_FILES%\MyUtility\X86</PROPERTY>
<PROPERTY ID="CommandLine" Protected="true"/>
<PROPERTY ID="CPU" Protected="true">X86</PROPERTY>
</PROPERTYCONTAINER>
<FILECONTAINER>
<FILE ID="FileList.exe"/>
</FILECONTAINER>
</PACKAGETYPE>
</PACKAGETYPECONTAINER>
<PROPERTYCONTAINER/>
</PACKAGE>
</PACKAGECONTAINER>
</ADDON>
</ADDONCONTAINER>
</xsl:template>
</xsl:stylesheet>
Using Packages
Build the FileList.cpp for all the required Platforms and place the binaries under ‘Program Files\MyUtility\<Arch>’ (e.g Program Files \MyUtility\Armv4I\FileList.exe).
Let’s modify the utility to make use of the package. We need to do 2 things for that
- Place the FileListPackage.xsl file in Global datastore directory (Documents and Settings\All users\Application Data\Microsoft\CoreCon\1.0\Addons).
- Replace the FeilDeployer.sendfile with FileDeployer.DownloadPackage
Replace the line
fileDeployer.SendFile("FileList.exe", @"%CSIDL_PROGRAM_FILES%\FileList.exe");
With the below 2 lines
ObjectId packageObjID = new ObjectId("0695ABA4-6A85-484d-8C07-5E67FE44D6BC");
fileDeployer.DownloadPackage(packageObjID);
Now, we have made the FileList Utility architecture agnostic. Won’t it be good if there is way to know whether my utility has started properly in device. Won't it be good if I could interact with my utility, send/receive inputs and make it more interactive. Yes all are good and possible using CoreCon APIs. We will see how to write a device agent and build a FileViewer of our own.
Let’s see some ways to do send/receive files to device and some process related functions. CoreCon provides a class called FileDeployer using which we can do file transfers across device and desktop. You should have established connection (Device.Connect()) to use the FileDeployer methods.
Device myDevice = GetPPC05Emulator();
myDevice.Connect();
FileDeployer fileDeployer = myDevice.GetFileDeployer();
fileDeployer.SendFile("foo.txt",@"%CSIDL_PROGRAM_FILES%\foo.txt");
This deploys the foo.txt (present in current directory) to “\Program files” folder in device. Note that you can use CSIDL paths in the both source and destination file names. CSIDL values provide a unique system-independent way to identify special folders used frequently by applications, but which may not have the same name or location on any given system. Similarly there are APIs to do receive file and deploy bunch of files (using package) at a time. I will be discussing about the packages in detail in following blogs.
RemoteProcess class gives us a way to start/stop process. Below code snippet starts a new process. Waits for some time (5 seconds), List all the process running and kills the started process.
Device myDevice = GetPPC05Emulator();
myDevice.Connect();
//Start the calculator process in device
RemoteProcess remoteProc = myDevice.GetRemoteProcess();
bool bStarted = remoteProc.Start(@"%CSIDL_WINDOWS%\calc.exe", " ");
//List all running process
Collection<RemoteProcess> remoteProcCollection = myDevice.GetRunningProcesses();
int num = 0;
foreach (RemoteProcess rproc in remoteProcCollection)
{
num++;
System.Console.WriteLine(num.ToString() + ". " + rproc.FileName);
}
//Kill the process
if (remoteProc.HasExited() == false)
{
remoteProc.Kill();
}
Let’s put all these together and write a small utility to do file listing in device. We will have a native app(FileList.exe) in device which will iterate the specified directory and print file names in a log. Our app will deploy this filelist.exe, run it with various parameters, get the log file and print in the console.
Create a Smartdevice console app targeting PPC 05. Copy paste the below code.
Source for FileList.cpp
/*
* Gets the list of files/directories present int the path specified in cmd line argument.
*/
int _tmain(int argc, _TCHAR* argv[])
{
int iRetVal = 0;
if(argc <=1)
{
//No args passed
return -1;
}
DeleteFile(L"\\foo.txt");
HANDLE hLog = CreateFile(L"\\foo.txt",GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hLog == INVALID_HANDLE_VALUE)
{
//Error in creating log file
return -1;
}
//Search the Directory
TCHAR* szPath = new TCHAR[_tcslen(argv[1]) + 4];
_tcscpy(szPath, argv[1]);
_tcscat(szPath, L"\\*");
WIN32_FIND_DATA findData;
HANDLE hSearchFiles = INVALID_HANDLE_VALUE;
hSearchFiles = FindFirstFile(szPath, &findData);
if(hSearchFiles != INVALID_HANDLE_VALUE)
{
do
{
TCHAR* szBuffer = new TCHAR[_tcslen(findData.cFileName) + 4];
_tcscpy(szBuffer, findData.cFileName );
_tcscat(szBuffer,L"\r\n");
DWORD numBytes;
WriteFile(hLog, szBuffer, _tcslen(szBuffer)*sizeof(TCHAR), &numBytes, NULL);
delete[] szBuffer;
}while(FindNextFile(hSearchFiles, &findData)) ;
}
else
{
iRetVal = -1;
}
//Clean up
if(szPath != NULL)
{
delete[] szPath;
szPath = NULL;
}
if(hLog != INVALID_HANDLE_VALUE)
CloseHandle(hLog);
if(hSearchFiles != INVALID_HANDLE_VALUE)
CloseHandle(hSearchFiles);
return iRetVal;
}
Create a C# console application. Copy paste the below code in program.cs.
Place the FileList.exe in the same directory as output directory.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SmartDevice.Connectivity;
using System.Collections.ObjectModel;
namespace sample1
{
class Program
{
static void Main(string[] args)
{
Device myDevice = GetPPC05Emulator();
//Connect to the device.
myDevice.Connect();
FileDeployer fileDeployer = myDevice.GetFileDeployer();
fileDeployer.SendFile("FileList.exe", @"%CSIDL_PROGRAM_FILES%\FileList.exe");
//Start FileList process in device
RemoteProcess remoteProc = myDevice.GetRemoteProcess();
bool bStarted = remoteProc.Start(@"%CSIDL_PROGRAM_FILES%\FileList.exe", @"\Program files");
if (bStarted == true)
{
while (remoteProc.HasExited() == false)
{
System.Threading.Thread.Sleep(2000);
}
}
int exitCode = remoteProc.GetExitCode();
if (exitCode == 0)
{
fileDeployer.ReceiveFile(@"\foo.txt", "Filelist.txt");
}
}
static Device GetPPC05Emulator()
{
DatastoreManager dsmgrObj = new DatastoreManager(1033);
ObjectId ppc05PlatObjID = new ObjectId("4118C335-430C-497f-BE48-11C3316B135E");
ObjectId PPC05EmuID = new ObjectId("25D984D9-0DFE-4DB1-A5A0-9A4F660BF2CE");
Platform ppc05Plat = dsmgrObj.GetPlatform(ppc05PlatObjID);
Device ppc05Emu = ppc05Plat.GetDevice(PPC05EmuID);
return ppc05Emu;
}
}
}
Now, this utility could be used to do file listing of device.
--
Anand R
VSD is shipping Set of connectivity API which could be used to write remote tools (Remote file viewer etc) kind of Apps. This series of blog is aimed at giving an introduction about the connectivity APIs.
Datastore is a set of XML files on your desktop computer that contains information about the platforms, devices, emulators, and packages that are installed on the computer. The contents of the Datastore are modified whenever you install an SDK that is based on Windows CE such as Windows Mobile. Let’s start with an app which looks at the datastore and enumerate list of SDKs and devices installed in the machine.
[Create a new C# Desktop console application. Add reference to Microsoft.Smartdevice.Connectivity.dll which can be found at <systemdrive>:\Program files\Common Files\Microsoft Shared\CoreCon\1.0\Bin ]
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SmartDevice.Connectivity;
using System.Collections.ObjectModel;
namespace sample1
{
class Program
{
static void Main(string[] args)
{
//Instead of 1033 use the locale ID of your app.
DatastoreManager dsmgrObj = new DatastoreManager(1033);
//Get all the platform entries present in Data store
//Iterate through Collection of platforms
Collection<Platform> platformCollection = dsmgrObj.GetPlatforms();
foreach (Platform objplatform in platformCollection)
{
System.Console.WriteLine(objplatform.Name);
Collection<Device> deviceCollection = objplatform.GetDevices();
//List all the devices in the platform
foreach (Device objdevice in deviceCollection)
{
System.Console.WriteLine("\t" + objdevice.Name);
}
}
}
}
}
Let’s look at some options to connect to a device and get info regarding the device.
In the below sample I am connecting to PPC 05 emulator and getting info regarding virtual and physical memory. IDs of devices/SDK can be obtained from the datastore files which can be found in
<sysDrive>:\Documents and Settings\<username> \Local Settings\Application Data\Microsoft\CoreCon\1.0 (Non Vista OS) or <sysDrive>:\users\<username>\Application data\Microsoft\CoreCon\1.0 (Vista)
Open the conman_ds_platform.xsl file in visual studio. This file contains the information about all the installed SDKs.
DatastoreManager dsmgrObj = new DatastoreManager(1033);
ObjectId ppc05PlatObjID = new ObjectId("4118C335-430C-497f-BE48-11C3316B135E");
ObjectId PPC05EmuID = new ObjectId("25D984D9-0DFE-4DB1-A5A0-9A4F660BF2CE");
Platform ppc05Plat = dsmgrObj.GetPlatform(ppc05PlatObjID);
Device ppc05Emu = ppc05Plat.GetDevice(PPC05EmuID);
//Connect to the device.
ppc05Emu.Connect();
SystemInfo pp05EmuInfo = ppc05Emu.GetSystemInfo();
System.Console.WriteLine("Available Physical Memoory\t:\t"+pp05EmuInfo.AvailPhys);
System.Console.WriteLine("Total Physical Memoory \t:\t" + pp05EmuInfo.TotalPhys);
System.Console.WriteLine("Available Virtual Memoory \t:\t" + pp05EmuInfo.AvailVirtual);
System.Console.WriteLine("Total Physical Memoory \t:\t" + pp05EmuInfo.TotalVirtual);
System.Console.WriteLine("OS Major number \t:\t" + pp05EmuInfo.OSMajor);
System.Console.WriteLine("OS Minor number \t:\t" + pp05EmuInfo.OSMinor);
--
Anand R
A few days ago Visual Studio "Orcas" Beta 1 was made available for download. We also handed out DVDs at MEDC 2007 Las Vegas Last week. I hope you were able to install these bits and try out some of the new features we enabled.
If you have not downloaded these Bits yet you could do so from http://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx . It also has details on how to log bugs and suggestions with the Product Team.
or you can just use our Blog to share your feedback.
Thanks
Amit Chopra
Program Manager VSD Team
Unless you've been living under a rock, you're probably aware that we shipped Visual Studio Orcas Beta1 last week. Here's Soma's blog post on the release which also has a link to the download. This is a huge milestone for us as the product that we've been carving out with love for the last year or so is coming together and you can see the final shape.
For the VSD team, unit testing for NetCF(which we blogged about here) is a big-ticket item and we're super excited that you're finally seeing it in its close-to-final form.
Testing non-public methods in Beta1
If you try to generate unit tests for a non-public method in Beta1, you'll see a comment saying "Generation of unit tests for private methods of device projects not supported". Don't panic - this is a temporary placeholder while we fixed a few issues with the code generation. You won't see this in the the next CTP/Beta for Orcas (as we've already fixed it internally). In the meantime, here's how you can easily work around this by writing a few lines of code and using the Smart Device Unit Test Framework.
In a nutshell, you can use the PrivateType and PrivateObject types found in the unit test framework to get at the ‘privates’ of your code. Let’s look at a detailed example
Step1: Lets generate some code
First of all lets generate some test code for below application which contains different kinds of non-public constructs. How to generate code can be found at http://msdn2.microsoft.com/en-us/library/ms364064(vs.80).aspx
using System;
using System.Collections.Generic;
using System.Text;
namespace BankAccountDemo.Business
{
class BankAccount
{
// Properties
private int _accountno;
private float _currentBalance;
private static float _bankAsset;
private static int _newUniqueAccountno;
private static int GetUniqueAccountNo
{
get {return _newUniqueAccountno++;}
}
private float CurrentBalance
{
get { return _currentBalance; }
set { _currentBalance = value; }
}
// Constructors for new account
private BankAccount(float initialBalance)
{
this._accountno = GetUniqueAccountNo;
this._currentBalance = initialBalance;
}
// Methods
private float DepositMoney(float depositAmount)
{
this.CurrentBalance += depositAmount;
_bankAsset += depositAmount;
return this.CurrentBalance;
}
private float WithdrawMoney(float withdrawAmount)
{
this.CurrentBalance -= withdrawAmount;
_bankAsset -= withdrawAmount;
return this.CurrentBalance;
}
private static float BankAsset()
{
return _bankAsset;
}
}
}
Step2: Add accessor class in Test Project to ease accessing the non-public code
Add a class to the test project (we call it BankAccountPrivateAccess in the example below). This class will contain the private accessor methods which can be used by testmethods to access non-public code
using System;
using System.Collections.Generic;
using System.Text;
using BankAccountDemo.Business;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject2
{
/// <summary>
/// Accessor Class for BankAccount
/// </summary>
public class BankAccountPrivateAccess
{
PrivateObject m_privateObject;
static PrivateType m_privateType =
new PrivateType("SmartDeviceProject2",
"BankAccountDemo.Business.BankAccount");
/// <summary>
/// Constuctor initializing private object to invoke methods
/// </summary>
/// <param name="target"></param>
public BankAccountPrivateAccess(object target)
{
m_privateObject = new PrivateObject(target,m_privateType);
}
/// <summary>
/// Return target object of non-public class to be tested
/// </summary>
/// <param name="target"></param>
public static object CreatePrivate(float initialBalance)
{
object[] args = new object[] { initialBalance };
PrivateObject priv_obj =
new PrivateObject("SmartDeviceProject2",
"BankAccountDemo.Business.BankAccount",
new System.Type[] { typeof(float) }, args);
return priv_obj.Target;
}
}
}
Step3: Add Private Accessor methods and properties in above class to access non-public methods and properties
Add the following method to access method DepositMoney
public float DepositMoney(float depositAmount)
{
object[] args = new object[] { depositAmount };
return ((float)(m_privateObject.Invoke
("DepositMoney", new Type[] {typeof(float)}, args)));
}
Add the following method to access static method BankAsset
public static float BankAsset()
{
object[] args = new object[0];
return ((float)(m_privateType.InvokeStatic
("BankAsset", new System.Type[0], args)));
}
Add following method to access property CurrentBalance
public float CurrentBalance
{
get
{
return ((float)(m_privateObject.GetProperty("CurrentBalance")));
}
set
{
m_privateObject.SetProperty("CurrentBalance", value);
}
}
Add following property to access static property GetUniqueAccountNo
public static int GetUniqueAccountNo
{
get
{
return ((int)(m_privateType.GetStaticProperty("GetUniqueAccountNo")));
}
}
You can use similar code to access any other member you have.
Step4: Modify the Generated Test Code to call methods of accessor class
Add following code to Test Deposit Money Test method
// TODO: Initialize to an appropriate value
object param0 = BankAccountPrivateAccess.CreatePrivate(5000);
// TODO: Initialize to an appropriate value
BankAccountPrivateAccess target = new BankAccountPrivateAccess(param0);
// TODO: Initialize to an appropriate value
float depositAmount = 0F;
// TODO: Initialize to an appropriate value
float expected = 0F;
float actual;
actual = target.DepositMoney(depositAmount);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("Verify the correctness of this test method.");
Modify the other testmethods to use your accessor class as well.
Voila! Your code is now testable using Orcas. Remember that this workaround is temporary – you won’t need to do any of this the next time you get Orcas bits.
If you're using the new Windows Mobile 6 SDK, you might find that your breakpoints don't get hit anymore when you're debugging a managed application. In this case, check the NetCF version you have installed on the desktop - ensure that it is NetCF V2 *SP1* or above. Note that Windows Mobile 6 has NetCF v2 SP1 pre-installed and the SDK setup asks you to install V2 SP1 on your desktop machine if you didn't have it installed.
The reason you see this behavior is due to a bug which existed in NetCF v2 RTM's icordbg.dll that we have fixed in SP1.
For those of you developing on Windows Vista, the much awaited for Device Emulator V2 is now live.
Check out: http://blogs.msdn.com/anandba/archive/2007/03/13/device-emulator-v2-is-live.aspx for details.
Anand Balachandran
Issue:
Developers who upgraded to VS 2005 SP1 from VS 2005 RTM may have noticed issues in their connectivity. When they try to connect to device they will be getting one of the following error messages depending on whether you have ActiveSync installed in your machine or not.
- ActiveSync not installed
- Device is not ready
Reason:
In VS 2005 SP1 we did some bug fixes in conman2.dll (desktop side component) and conmanclient.exe (device side component). When you install SP1 both conman2.dll and conmanclient.exe (along with other binaries) get updated. If you have RTM version of conmanclient.exe running in your device then connection from desktop will fail (as the expected version of conmanclient.exe is not present in device).
If desktop component finds that conmanclient.exe is not of the same version it tries to shut it down, bootstrap the device (copy the device side binaries to device and start them). In case of WinCE devices (e.g. CEPC), bootstrap being manual, will try to use ActiveSync and fails with an error message if the device is not connected through ActiveSync.
In case of emulator saved states this won't be any problem. Desktop will be able to re-bootstrap the emulator using DMA bootstrap. Because of the extra bootstrap, time to connect to the emulator saved state will slightly increase.
How to solve this:
If you have wince device with RTM binaries (conmanclient.exe, CMAcept.exe) then replace them with the SP1 binaries. Then run conmanclient.exe and cmaccept.exe from device. Now try the connection from desktop.
In case of emulator, connect to the emulator once using SP1. Now the newer (SP1) binaries will be present in the emulator. Create a fresh saved state out of this.
---
Anand R
Yes VS 2005 SP1 is now available for download. Here are some useful links I wanted to share.
So as a device developer what should you expect ? Some big areas we touched upon were:
- We Added Development Support for Windows Embedded 6.0 platform based devices
Ability to develop using SQL Server 2005 Compact Edition
Added 15 Device Side MFC Classes to MFC for Devices
Fixed issues with eVC to VS 2005 Migration Wizard
Updated to the latest Version of Device Side Native Compilers
Included the latest versions of the Windows CE Remote Tools
and many other bug fixes both from our team as well as other teams we work with.
Thanks
Amit
This blog post should have happened some time ago and the only reason it has taken so long is due to my laziness :-)
With the recent Visual Studio Orcas CTPs, we are shipping preview bits of one of the biggest features Visual Studio for Devices has to offer for Orcas - unit testing for NetCF applications.
We would love to get feedback/britbats. Note that these are very, very early bits - so please be gentle :-). Here's how you can try it out. Leave a comment or mail any feedback to sriramk at microsoft.com.
Preparation
- Download the CTP
- Make sure your target device or emulator already has NetCF v2 installed. We will *not* deploy it automatically. The easiest way to do this is to simply deploy a v2 project
Steps to run your first device unit test
- Create a NetCF v2 project. Can be anything other than Console Application (we have a bug around Console Applications that will be fixed in the next release)
- On any method, right-click and choose 'Create Unit Tests'
- From the dialog that pops up, choose 'Create a new Smart Device Visual C# Test Project' (or the equivalent VB one). Go ahead and create the test project.
- You should now see a spanking new test project. Go ahead and type in your unit test code. You know you want to :-)
- Click on Test->Windows->Test Manager. You should see a list of all your unit tests.
- Check 'All Loaded Tests'
- Click on 'Run Checked Tests' (the button with the green arrow)
- Voila! Your tests should run and you'll see the results in the test results window
Sriram Krishnan
What is Platform Verification Task?
Smart Device development involves writing applications that target a particular device platform. Toolbox filtering, the unsupported control designer and IntelliSense provide design time aid to the developer to add only PMEs (properties/methods/events) supported by the current platform to his application. But in certain scenarios the developer might have written an application for a particular platform and then ported it to another platform. In this scenario it is necessary to identify the PMEs not supported by the new platform at build time. These errors cannot be caught by simply compiling the project against NETCF assemblies (For example, if your project contains a "Button" control, then, building it against the NETCF system assemblies will always succeed, since "System.Windows.Forms.Button" is a supported NETCF control. But "System.Windows.Forms.Button" is not supported by all device platforms (For example, Smartphone does not support it)). Platform Verification Task (PVT) is a post-build validation step to catch the unsupported PMEs before they can result in a runtime exception.
Just another MSBuild target:
So what is this post build step and how does fit into Visual Studio build system? As you might be aware VS2005 uses the MSBuild engine from the IDE to perform all compile time actions. The project file contains the information about the set of target files (which contain the list of MSBuild targets) that need to be imported and executed by the MSBuild engine. The set of targets specific to Smart Device projects are defined in Microsoft.CompactFramework.Common.targets file (installed in the System .NET Framework directory) and are imported inside each Smart device project’s project file.
Platform Verification task is one of the MSBuild targets added to Microsoft.CompactFramework.Common.targets file which is executed after the project has been built. If project build is successful, then PVT is executed with the following parameters:
1) PlatformFamilyName (example, PocketPC)
2) PlatformID (example, ID corresponding to PPC2003)
3) SourceAssembly name
4) ReferencePath, i.e. assembly path
5) TreatWarningsAsErrors , a flag specifying whether PVT should generate Warnings or Errors and
6) PlatformVersion (example NETCF v2)
What is required? A managed code analysis tool to examine the managed assemblies for correctness issues. Every managed code developer already uses it, isn’t it?
As stated above, PVT is not a build time step. What this means is that PVT does not parse the source code to identify unsupported PMEs. It parses the IL to do the same work. This is where FXCop comes into picture. FXCop architecture provides the necessary extensibility to define customized FXCop rules. FXCop rules are generally used to identify violations of design guidelines in the code, but the user can define just about any policy specific to his requirement.
FXCop has three main facets:
1) Targets - the assemblies to be analyzed
2) Rules - the checks to be performed
3) Messages - the output from the rules
PVT internally implements a customized FXCop rule which performs the checks for unsupported PMEs.
So how does it all work?
The basic control flow is as follows:
1) PVT is invoked with the necessary parameters mentioned above.
2) It identifies the list of assemblies referenced by the source assembly and loads the metadata in the platform specific asmmeta assemblies corresponding to each of the referenced assemblies. (Platform specific asmmeta assemblies are assmeta files which contains the information about platform’s supported PMEs. For each platform there is one assmeta file provided by NETCF. The files are located under %Program files%\Microsoft Visual Studio 8\smartdevices\sdk folder)
3) PVT then executes a customized FXCop rule (PlatformVerificationRule) with this metadata and the source assembly.
4) PlatformVerificationRule (PVR) parses the IL; in fact, it is the base FXCop rule that does the parsing. The FXCop analysis engine uses Reflection exposed type system in the assemblies to disassemble IL, build color graphs from assemblies and create control flow graphs from Method. The base FXCop rule lets you ask for higher-level constructs in the MSIL for the code. For identifying whether the application is conformant to the target platform, PVT needs to perform checks only for some constructs (ones which can access platform unsupported PMEs). Hence it overrides the methods which are called when following constructs are identified in the assembly:
a. Constructor
b. Expression statement
5) For the above construct types, it performs the following checks in the corresponding overridden methods:
c. Constructor: In this method, PVR gets the assmeta type of the object getting instantiated and checks whether this type has “SupportedAttribute” attribute set to false. If yes, it generates a message for each violation.
d. Expression statement: In this method, PVR checks if the expression statement involves a method call. If so, it gets the assmeta type for the type on which the method is getting called and checks whether this type has “SupportedAttribute” attribute set to false. It also gets the asmmeta type for the method getting called and checks whether it has “SupportedAttribute” attribute set to false. For each violation a Message is generated.
6) The Messages are then output as Warning/Errors.
Disabling PlatformVerificationTask: If it is so useful, why will I disable it at all?
Though Platform Verification Task aids the developer in identifying all the unsupported PMEs getting accessed in code at build time itself, it does add quite a bit to the build time. Ideally the developer might like to run PVT only once in a while and not during every build. Currently there is no support in the VS2005 IDE to customize the execution of PVT during build, though we are looking to add support for it in next release. As a workaround for VS2005, PVT execution can be customized by following the steps below:
1) Open the file %windir%\Microsoft.NET\Framework\v2.0.50727\Microsoft.CompactFramework.Common.Targets for editing.
2) Go to the line which reads:
Name="PlatformVerificationTask">
and change it to:
Name="PlatformVerificationTask" Condition="'$(SkipPlatformVerification)' != 'true'">
3) Add the SkipPlatformVerification environment variable to the system and set it to "true" (To re-enable Platform Verification set the environment variable to "false")
4) Restart Visual Studio for the changes to take effect (If building from the command line using MSBuild, add /p:SkipPlatformVerification=true to your command line to turn off the task. You can specify the variable in the project file also, so that this information is persisted across sessions).
Rory Blyth, an MSDN Events Presenter, plans to give a series of screencasts on the subject of Windows Mobile Development. You can access the link here.
In his own words:
"I've decided, humble as I am, to try and create the greatest series of screencasts in the entire universe on the subject of Windows Mobile development. I'll probably fail, but that's no big deal. It's just a goal.
In this first screencast, I walk you through the creation of a very simple Windows Mobile application, while pointing out some things you Need To Know along the way.
Future screencasts in this series will be deeper technical dives, but you gotta start somewhere, eh? I hope you like it"
Enjoy!
--Anand
Barry has just posted details on this
here. For all you geeks out there, this is an incredible opportunity to peek into the innards of the device emulator
[Sriram]