Introduction & Background
I recently worked on an application that utilizes the .NET Compact Framework 2.0. We have an application counterpart that is installed on the Desktop, which manages sending files originally created on Handheld Devices over a B2B service.
We have had file-corruption problems in the past involving Microsoft ActiveSync. Let me make it clear that I am not stating that ActiveSync was directly responsible for the problems. We have a unique requirement that requires us to perform a second type of synchronization, which is between a local working folder and the synchronized files from the Handheld Device which resides on the desktop computer.
As I started strategizing on how to approach dealing with these synchronization conflicts, I realized something: we don't actually need to synchronize files, we just need to copy them! Due to the way we have designed our software, various XML files are created on the Handheld Devices, and then our Desktop software takes those XML files, sometimes tweaking the data, and then produces data files that it transmits over a B2B service.
So I got to thinking. What if I just yanked the files directly off the Handheld Device? Performing this activity was new to me, information on this topic was hard to find, and that is what prompted me to write this article!
Note: This code has only been tested for Window Mobile 5 devices.
Google, CodeProject, and OpenNetCF
Believe it or not, for someone (me) who has not done it before, figuring out how to find and manage files on a Handheld Device from a desktop application was not easy. Google, Google Groups, CodeProject, and a myriad of other sites were not helpful. The best I could find was articles for managing a known file. I needed to be able to enumerate an entire directory structure on the Handheld Device.
I then came across OpenNetCF (OpenNetCF[^]). The have an Open Source DLL called OpenNETCF.Desktop.Communication.dll. This can be downloaded here[^].
Although OpenNetCf.Desktop.Communication.dll is very handy, I found it a bit difficult to work with. I like to see examples of how to use objects. I decided to write a kind of wrapper class around this DLL, simplifying all the tasks I needed to perform with Handheld Device files. Those tasks are listed in the following tests:
OpenNETCF.Desktop.Communication Assembly
RAPI (Remote API) via OpenNETCF.Desktop.Communication.dll is what allows us to work with the Handheld Device. I will touch lightly on some of the methods and properties available in this assembly.
RAPI.DevicePresent
This property returns a boolean, and is true
if a device is connected to your computer.
RAPI.Connect()
, RAPI.Disconnect()
Prior to working with your device, you must connect to it via RAPI. When you're done, you should disconnect.
RAPI rapi = new RAPI();
rapi.Connect();
rapi.Disconnect();
RAPI.EnumFiles
FileList RAPI.EnumFiles(string fileName)
is what allows us to get files and directories from the Handheld Device. What's a little confusing is the string fileName
part. The following are valid string arguments which can be passed into the RAPI.EnumFiles
method:
My Documents\\Folder1\\ |
This will return one item, Folder1 , in the FileList array. |
My Documents\\Folder1\\* |
This will return all files and directories within Folder1 in the FileList array. |
My Documents\\Folder1\\*xml |
This will return all XML files within Folder1 in the FileList array. |
My Documents\\Folder1\\123.xml |
This will return one item, 123.xml in the FileList array. |
HHFiles.cs
I've included my HHFiles
class here. The following are some code snippets from this class.
Access the My Documents directory on the Handheld:
public FileList MyDocuments
{
get
{
return rapi.EnumFiles("My Documents");
}
}
public void CopyFileFromDevice(string localFilePath,
string deviceFilePath, bool overwrite)
{
Rapi.CopyFileFromDevice(localFilePath,deviceFilePath,overwrite);
}
Example:
HHFiles files = new HHFiles();
files.CopyFileFromDevice(@"c:\test.txt",
@"My Documents\Folder\Somefile.txt,true);
Delete a file on the Handheld:
public void DeleteFile(string deviceFilePath)
{
if (Rapi.DeviceFileExists(deviceFilePath))
{
Rapi.DeleteDeviceFile(deviceFilePath);
}
}
Copy files recursively from, including the directory structure.
public void CopyFilesFromDevice(string localStartingDirectory,
string deviceStartingDirectory,
string fileMask,
bool includeSubDirectories,
bool overwrite)
{
CreateLocalStartingDirectory(localStartingDirectory);
FileList deviceDirectory = GetFileList(deviceStartingDirectory);
if (deviceDirectory == null || deviceDirectory.Count != 1)
{
throw new System.IO.FileNotFoundException("Invalid Device Directory",
deviceStartingDirectory);
}
FileList directoryList = GetFileList(deviceStartingDirectory + "\\*");
foreach (FileInformation dirInfo in directoryList)
{
if (dirInfo.FileAttributes == (int) FileAttributes.Directory )
{
if (!includeSubDirectories) continue;
string newDeviceDirectory =
deviceStartingDirectory + "\\" + dirInfo.FileName;
string newLocalDirectory =
localStartingDirectory + "\\" + dirInfo.FileName;
CopyFilesFromDevice(newLocalDirectory,
newDeviceDirectory,fileMask,includeSubDirectories,overwrite);
}
else
{
if (!MatchesFileMask(dirInfo.FileName, fileMask)) continue;
string newDeviceFile =
deviceStartingDirectory + "\\" + dirInfo.FileName;
string newLocalFile =
localStartingDirectory + "\\" + dirInfo.FileName;
CopyFileFromDevice(newLocalFile,newDeviceFile,overwrite);
}
}
}
Example:
HHFiles files = new HHFiles();
files.CopyFilesFromDevice(@"c:\temp", @"My Documents\Work","xml",true,true);
Conclusion
Well, it's been a little while since I wrote an article. I hope that you find this useful. I spent a lot of time trying to figure out how to deal with files on a Handheld Device, and this class has greatly simplified the work. If anything is unclear, or you have any question, I'll check back frequently, so please just post your question.