Thursday, April 29, 2010

How to enumerate files on a Windows CE based device from the Desktop

In this article I'd like to demonstrate how to enumerate files on a Windows CE based device from the desktop.

Listing the contents of a directly on a Windows CE from the desktop is something I found to be useful every now and then. It involves using the Remote API and ActiveSync / Windows Mobile Device Center

As usual this will involve a few P/Invokes:

[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
static extern int CeRapiInit();
 
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
static extern int CeRapiUninit();
 
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CeFindFirstFile(string lpFileName, ref CE_FIND_DATA lpFindFileData);
 
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
static extern bool CeFindNextFile(IntPtr hFindFile, ref CE_FIND_DATA lpFindFileData);
 
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
static extern bool CeFindClose(IntPtr hFindFile);


We also need the CE_FIND_DATA structure

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct CE_FIND_DATA
{
    public int dwFileAttributes;
    public FILETIME ftCreationTime;
    public FILETIME ftLastAccessTime;
    public FILETIME ftLastWriteTime;
    public int nFileSizeHigh;
    public int nFileSizeLow;
    public int dwOID;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string cFileName;
};
 
[StructLayout(LayoutKind.Sequential)]
struct FILETIME
{
    public int dwLowDateTime;
    public int dwHighDateTime;
}


The CeRapiInit method has be always called before performing Remote API operations. Once done, the CeRapiUninit must be called. For listing the files in a directory, I use CeFindFirstFile, CeFindNextFile, and CeFindClose. How this works: If the file(s) exists CeFindFirstFile will return a valid handle that can be used for calling CeFindNextFile. After going through all the files CeFindNextFile will return false and a call to CeFindClose needs to be called.

public static string[] GetFiles(string remoteDirectory)
{
    try
    {
        CeRapiInit();
 
        var list = new List<string>();
        var findData = new CE_FIND_DATA();
        var hFindFile = CeFindFirstFile(remoteDirectory + "\\*", ref findData);
 
        if (hFindFile != new IntPtr(-1))
        {
            try
            {
                do
                {
                    if (findData.dwFileAttributes != (int)FileAttributes.Directory)
                        list.Add(findData.cFileName);
                } while (CeFindNextFile(hFindFile, ref findData));
            }
            finally
            {
                CeFindClose(hFindFile);
            }
        }
 
        return list.ToArray();
    }
    finally
    {
        CeRapiUninit();
    }
}


I hope you found this useful.

2 comments:

Josué Bolivar said...

Very good post, it works very well. Thanks for share it.
Saludos from Chile

Josué Bolivar said...


Very good post, it works very well. Thanks for share it.
Saludos from Chile