With
the introduction of Windows Embedded Compact 2013 (aka Windows CE 8.0), the
good old File Explorer is no longer present. On itself I understand why
Microsoft did this - what end-user application needs a File Explorer? - but
during DEBUG development, it was/is a helpful tool.
So what are your options as a developer (debugger)?
- Add the Command Shell to your image. Ok if you can type fast (I am not)
- Add the Telnet Server to your image. Ok if you can type fast (I am not)
- Add the Ftp File Server to your image and use that one for Remote File
Manager
- Add the Smb File Server to your image. Unfortunally this one is also no
longer available under Windows CE 8.0
I
use now the Ftp File Server as a replacement for the File Explorer. It is
not as powerful as the old File Explorer or Smb File Server, but will do for
the most things I need to do (copying files, typically from my development PC
to the device and back).
But the Ftp File Server has always been sloooow in copying files back and forth
to the device's local file system, especially when you copy files to slow hard
disks (like some Compact Flash cards).
Unless you make a few minor changes to the code.
I will show you what you need to change in the Ftp File Server to make it fast
enough to be used as a reasonable replacement.
The
main problem with the Ftp File Server is located in method
CFtpSession::ReceiveFile().
It reserves a small buffer (4Kb) to accept the data from the socket and then
copies this data to the hard disk. It repeats this in a loop until the whole
file is copied.
- The
first step is to enlarge the buffer.
But this is not enough, the main problem with the implemented approach is that
the buffer is not always entirely filled up till the full 4Kb, but to whatever
the socket returns in the recv() call. And this is most of the time less than
the buffer size you specify. Moreover, if you have a slow hard disk and you
copy the partially filled buffer to the hard disk, this turns out to be very
ineffective.
- It
is better to choose the buffer size to best fit the ATAPI’s internal
buffer size (typically 4Kb or 64Kb aligned) and to fill it completely (by
continuously reading the socket) before to start the slow copy to the hard
disk. Practically I choose the buffer size as 64Kb.
With
this approach I could speed up Ftp file transfer to the device with a factor of
5 on some slow compact flash disks. Here are my speed improvement code changes:
const int size = 65536;
char *_ab
= new char
[size];
int
inbuffer=0;
do
{
inbuffer=0;
do
{
dwCount = recv(_sockData, (char *)(_ab+inbuffer), size-inbuffer, 0);
inbuffer += dwCount;
// DEBUGMSG
(ZONE_RW, (TEXT("FTP_ReceiveFile at %d bytes/call. Buffer=%d\r\n"),
dwCount, inbuffer));
} while ((dwCount != SOCKET_ERROR) && (dwCount
> 0) && (size-inbuffer > 0));
if
((dwCount != SOCKET_ERROR) && ((int)inbuffer
> 0))
{
bRet = WriteFile(hFile,
_ab, inbuffer, &dwRet, NULL);
dwTotalRecv += dwRet;
}
} while((bRet) && (_sockData != INVALID_SOCKET)
&& (dwCount > 0) && (dwCount != SOCKET_ERROR) &&
(inbuffer == dwRet));
delete
_ab; _ab = NULL;
Note that I dynamically allocate the 64kB buffer. This is because this code dates back from Windows CE 4.x/5.0 when memory was scarse. You might as well create it statically or local on the stack.
The
Ftp server by default (as shipped by Microsoft) cannot delete or overwrite
read-only files. Therefore I always make sure the Ftp Server is only accessible
with proper login credentials (although user and password are transmitted in
clear text over the wire => not secure), once you are authenticated as admin
(ALLOW_WRITE permission), I think it makes sense to have full write access. I
modified the code further up in source with my own code as follows:
WCHAR szFileCopy[MAX_PATH];
wcscpy(szFileCopy, szFile);
wcscat(szFileCopy, L".ftpd.bak");
// Make a .bak
file of the existing file in case the copy fails (so we still have a backup of
the original file)
if (bRet
&& bExists)
{
DWORD dwAttributes =
GetFileAttributes(szFileCopy);
dwAttributes &=
~FILE_ATTRIBUTE_READONLY; // Make file writable prior to deleting it. We have
ALLOW_WRITE permission.
SetFileAttributes(szFileCopy,
dwAttributes);
DeleteFile(szFileCopy); // Delete previous copy, if any
bRet = MoveFile(szFile,
szFileCopy); // Move current file to copy
}
// Do the copy
if (bRet)
{
// In
case the file exists, we will delete it by removing the read-only flag first
// Note
that when the file exists,
szTempFile != szFile ==> szFile can
be deleted
// Note
that when the file doesn't exist,
szTempFile == szFile ==> szFile cannot be deleted
if
(bExists)
{
DWORD dwAttributes =
GetFileAttributes(szFile);
dwAttributes &=
~FILE_ATTRIBUTE_READONLY; // Make file
writable prior to deleting it. We have ALLOW_WRITE permission.
SetFileAttributes(szFile,
dwAttributes);
DeleteFile(szFile); // Delete current
file, there should be not one!
}
bRet = MoveFile(szTempFile, szFile); //
Move temp file to new file
}
// In case the
copy succeeded, we can remove the .bak file
if (bRet
&& bExists)
{
DWORD dwAttributes =
GetFileAttributes(szFileCopy);
dwAttributes &=
~FILE_ATTRIBUTE_READONLY; // Make file writable prior to deleting it. We have
ALLOW_WRITE permission.
SetFileAttributes(szFileCopy,
dwAttributes);
DeleteFile(szFileCopy);
}
Note:
- If
you are familiar with building your own Windows CE image, you should know it is
not a good idea to make changes in the PUBLIC folder. Instead make a copy,
typically in your PLATFORM folder, make it buildable and do your changes there.
- I
also used to patch the Smb File Server for a few bugs and speed enhancements.
Basically I use the same tricks as described for the Ftp File Server. You can
quite easily port it from Windows CE 6.0 or 7.0 and add it to your DEBUG image.
Maybe I'll blog on that in the future.