I remember when I first started using the internet (in 1993 using Winsock on a 14400 USR sportster modem) about just how exciting it was to no longer feel isolated on my computer. Nevertheless, it has still taken me 10 years or so to actually start programming for it - no-one ever said I ran before I could walk! And it has really only come about as a result of writing ToDoList, an XML 'based' task-list-thingy, also posted on CodeProject.
And yet how was I still doing this uploading on a day-today basis? Using an FTP utility, that's how.
"And what's wrong with that", you may (or you may not) ask?
Nothing, from a strictly functional perspective, it's just that the process often strikes me as all so disjointed: saving a document in one app and then starting up a separate utility to transfer the file just screams at me for an overhaul.
What I really desired was to be able to simply call something like
GetFile() (or run a standalone app), optionally with no parameters, and have it present all the necessary GUI required to allow me to get any file from anywhere and in the manner to which I've become accustomed over the last 8-9 years, namely via something like the standard Open/Save dialogs.
And that is what I've tried to do here.
EasyFtp is a no-brainer utility (no disrespect to anyone out there without a brain) which simply wraps a bunch of classes which do all the work.
Note: The reason I've wrapped it as an EXE is to allow it to be supported by TodoList's 'Tool' interface. It can just as easily be used by dropping the classes directly into your own application as I will explain later.
I've already hinted at some of the requirements but here's a more exhaustive list:
- Visually straightforward and familiar.
- No configuration editing.
- No RC file resources (especially if it's meant to be leveraged into multiple apps).
- Totally free (always).
- Lightweight (mind you, it's MFC - all things are relative).
- Configurable - i.e. I can pass as much or as little information and the rest will be requested of me.
The basic workflows that I envisaged were these:
Sounds simple doesn't it?
And the beauty of it was that it was just as simple as it appears, taking into account (as I always do) that I had already written a lot of the code necessary to make it work for other projects.
And the particular code in question is
CRuntimeDlg which I first presented in ToDoList as a means of constructing dialog boxes without the use of the RC editor and the resultant dependency on RC based dialog templates.
Note: If you're not clear on why this is such a significant issue, consider what has to happen if you want to reuse code that relies on dialog resources:
- Copy/Include the .h/.cpp files.
- Copy the dialog resources from the .RC file.
- Verify that no nasty resource.h issues have arisen as a result of Visual Studio doing whatever it wants to ensure it can merge in the new resources.
CRuntimeDlg will allow you embed dialog control definitions within the dialog's .cpp file without any other fiddling about.
Any control (possibly except ActiveX, at present) that can be placed by Visual Studio's resource editor can also be used in a
CRuntimeDlg based dialog.
It all adds up to being able to move the files anywhere without a second thought - works for me every time.
This is a rather simplified diagram which shows the principal class relationships
: EasyFtp Class Diagram
|Orchestrates the |
|GUI and does the |
|uploading and |
---< downloading >--------
| ·-v---------------· |
uses| |uses |uses
| | |
.--------------v v------------------. v--------------------.
|CServerDialog | |CRemoteFileDialog | |CProgressDlg |
| | | | | |
|Retrieves the | |Remote version of | |Shows dload/uload |
|server details| |CFileDialog | |progress and doubles|
| | | | | as a cancel dialog |
·-------------v· ·v-----------------· ·v-------------------·
| | |
derived| |derived |derived
from| |from |from
| without resource |
(drawn courtesy of CodePlotter © AbstractSpoon 2003)
The rest of the code comprises of utility classes, the most interesting of which are:
::DeferWindowPos() offering handy additions like
::MapDialogRect() offering overloads to convert
longs, POINTs, SIZEs and RECTs to and from pixels and dialog units (DLUs).
Wrapper around the Windows system image list (which provides access to file icons).
CEdit derivative providing integrated browsing capabilities and using an enlarged non-client border in which to draw the file's icon.
Using EasyFtp (the utility)
By default, i.e. with nothing on the command line, EasyFtp will default to 'Download' mode, and will follow the workflow outlined above.
However, the following command line switches are available so that you can streamline or modify these defaults (note: switches must be preceded by - or /):
Specifies you want to upload a file, with nothing else on the command line this will display the workflow in the article image.
Specifies the remote path to upload to, or download from. This can be a full path (less the server bit) or just a folder, in which case it needs a trailing forward slash.
Specifies the local path to upload from, or download to. This can be a full path or a folder (no trailing backslash required).
Specifies the agent string to use (useful if EasyFtp is being spawned by another app).
Specifies the server location e.g.. www.microsoft.com.
Specifies the user name, if none is specified then an 'anonymous' login will be performed.
Specifies the password for the account, can be left blank if the username is blank.
Specifies anonymous login, empty username/password strings are passed.
Specifies _not_ to convert filenames to lowercase when uploading.
Specifies suppression of the 'confirm overwrite' dialog which appears if the upload or download target path already exists.
Using the code
If you would rather integrate the code directly into your own application then it's equally easy.
- Take all the files from the shared folder (in the zip file) and copy them to a single location anywhere you want.
- To the file you want to have FTP support, add the line
#include <span class="code-string">"[path]\remotefile.h"</span>
- Finally, wherever you want to download or upload files, add the code like this:
// note: this is straight out of EasyFtp.cpp
// uploading a file (downloading is almost identical)
// sLocalPath and sRemotePath will contain the user's
// choice on exit
// or simply "rf.SetFile()"
RMERR nErr = rf.SetFile(sLocalPath, sRemotePath);
// error handling
// note: if downloading we would now
// do something with the downloaded
// file pointed to by sLocalPath
sMessage.Format("Sorry, the requested upload to '%s' could not /
be completed for the following reason:\n\n%s",
sMessage.Format("Sorry, the upload of '%s' to '%s' could not /
be completed for the following reason:\n\n%s",
sLocalPath, sServer, rf.GetLastError());
AfxMessageBox(sMessage, MB_OK | MB_ICONEXCLAMATION);
- 1.0 - 25th Feb, 2004
- 1.0.1 - 26th Feb, 2004
- fixed bug where server dialog still pops up after canceling file open dialog (uploads only).
- fixed crash bug relating to not properly initializing the filename buffer pass to the file open dialog.
- 1.0.2 - 26th Feb, 2004
- fixed bug where Save As dialog was still appearing when the local path had been specified.
- 'nl' switch added to prevent remote upload pathnames being converted to lowercase.
- 1.1 - 10th Mar, 2004
- support added for drag'n'drop onto the application icon (in explorer or on the desktop). Note: this means that once you have setup the app command line to point to your FTP server you can do drag and drop uploading from your desktop.
- multiple files can now be uploaded or downloaded at once.
- various UI related bugs fixed.
- 1.3 - 23rd Mar, 2004 (not sure what happened to 1.2)
- many bugs fixed.
- anonymous login added. (Can be initialized using the -an command line switch.)
- confirmation dialog added if target upload or download file(s) exist. (Can be suppressed using the -nc switch.)
- improved error reporting, although I'm not yet translating HTTP errors.
- 1.3.1 25th Mar, 2004
- uxtheme.h/tmschema.h added to source code (thanks to Jay.ca).
- 1.3.2 27th Mar, 2004
- schemadef.h added to source code (thanks to Adnan).