Click here to Skip to main content
Click here to Skip to main content

EasyFtp 1.3.2 (for Applications)

By , 21 Mar 2004
 

Introduction

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.

I had decided on XML as the data format precisely because it could be uploaded to my web site and processed using JavaScript, to say nothing of XSL transforms and the myriad of opportunities this presents for reporting.

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.

Requirements

I've already hinted at some of the requirements but here's a more exhaustive list:

  • Visually straightforward and familiar.
  • No configuration editing.
  • Seamless.
  • 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.

Design

The basic workflows that I envisaged were these:

  • Uploading a file

    1. Show standard 'Open' dialog to elicit the local file to be uploaded.
    2. Show 'Server Details' dialog to retrieve server name, username and password.
    3. Log on to server and display remote 'Save As' dialog to retrieve the remote file path to upload to.
    4. Display a progress/cancel dialog during the upload.

    Note: These numbers correspond directly to the image numbers above.

  • Downloading a file

    1. Show 'Server Details' dialog to retrieve server name, username and password.
    2. Log on to server and display remote 'Open' dialog to retrieve the remote file path to download.
    3. Show standard 'Save As' dialog to elicit the local file to be saved to.
    4. Display a progress/cancel dialog during the download

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.

Instead, 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.

Implementation

This is a rather simplified diagram which shows the principal class relationships

{{DIAGRAM_START

: EasyFtp Class Diagram

                      .------------.
                      |CEasyFtpApp |
                      |            |
                      |Application |
                      |class       |
                      .v-----------·
                       |uses
                       |
                     .-v---------------.
                     |CRemoteFile      |
                     |                 |
                     |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
                 ------>v-----------------<------
                       |CRuntimeDlg       |
                       |                  |
                       |Implements dialogs|
                       | without resource |
                       |templates         |
                       |                  |
                       ·------------------·
}}DIAGRAM_END

(drawn courtesy of CodePlotter © AbstractSpoon 2003)

The rest of the code comprises of utility classes, the most interesting of which are:

  • CDeferWndMove

    Wrapper around ::DeferWindowPos() offering handy additions like OffsetCtrl() and ResizeCtrl().

  • CDlgUnits

    Wrapper around ::MapDialogRect() offering overloads to convert shorts, ints, longs, POINTs, SIZEs and RECTs to and from pixels and dialog units (DLUs).

  • CSysImageList

    Wrapper around the Windows system image list (which provides access to file icons).

  • CFileEdit

    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 /):

  • up

    Specifies you want to upload a file, with nothing else on the command line this will display the workflow in the article image.

  • rp

    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.

  • lp

    Specifies the local path to upload from, or download to. This can be a full path or a folder (no trailing backslash required).

  • ag

    Specifies the agent string to use (useful if EasyFtp is being spawned by another app).

  • sv

    Specifies the server location e.g.. www.microsoft.com.

  • us

    Specifies the user name, if none is specified then an 'anonymous' login will be performed.

  • pw

    Specifies the password for the account, can be left blank if the username is blank.

  • an

    Specifies anonymous login, empty username/password strings are passed.

  • nl

    Specifies _not_ to convert filenames to lowercase when uploading.

  • nc

    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.

  1. Take all the files from the shared folder (in the zip file) and copy them to a single location anywhere you want.
  2. To the file you want to have FTP support, add the line #include "[path]\remotefile.h"
  3. 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
    switch (nErr)
    {
        case RMERR_SUCCESS:
            // note: if downloading we would now 
            // do something with the downloaded
            // file pointed to by sLocalPath
            break;
    
        case RMERR_USERCANCELLED:
            break;
    
        default:
        {
            CString sMessage;
    
            if (sLocalPath.IsEmpty())
               sMessage.Format("Sorry, the requested upload to '%s' could not /
                                be completed for the following reason:\n\n%s",
                                sServer, rf.GetLastError());
            else
               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);
        }
        break;
    }

History

  • 1.0 - 25th Feb, 2004
    • Initial release.
  • 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).

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-ShareAlike 2.5 License

About the Author

.dan.g.
Software Developer Maptek
Australia Australia
Member
.dan.g. is a naturalised Australian and has been developing commercial windows software since 1998.
 
For all his latest freeware visit AbstractSpoon.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalobtaining the file sizemembermmontague19716 Dec '06 - 19:15 
Hello,
 
Thanks for this nice code. I'm using the class in my program, and it works great. One thing I'd like to do is to be able to obtain the file size. I wasn't sure what the easiest way to go about this was, so I ended up just adding a member function to the CRemoteFile class that is a modification of the CRemoteFile::GetFile() function.
 
It works, but I get an error message:
First-chance exception in MyProgram.exe (NTDLL.DLL): 0xC0000005: Access Violation
 
I'm wondering if there is an easier, better way to do get the file size that the way that I came up with:
 
long int CRemoteFile::GetFileSize(CString& sRemotePath, CString& sFileName, LPCTSTR szFilter, DWORD dwOptions)
{
ValidateOptions(dwOptions, TRUE);
 
RMERR nRes = RMERR_SUCCESS;
 
if (!EstablishConnection(nRes, dwOptions & !RMO_ALLOWDIALOG)) { // suppress default connection dialog
return -1;
}
 
// remote path(s)
CFRArray aRemoteFiles;
 
if (nRes == RMERR_SUCCESS)
{
sRemotePath.TrimLeft();
sRemotePath.TrimRight();
 
if (sRemotePath.IsEmpty())
nRes = GetRemotePaths(aRemoteFiles, dwOptions, szFilter);
else
{
sRemotePath.Replace('\\', '/');
 
// if the remote path ends in '/' then its a folder
// so we must still get the file
if (sRemotePath.GetAt(sRemotePath.GetLength() - 1) == '/')
nRes = GetRemotePaths(aRemoteFiles, dwOptions, szFilter, sRemotePath);
 
else // its a file
aRemoteFiles.Add(FILERESULT(sRemotePath));
}
}
 

long int file_size = -1;
if (nRes == RMERR_SUCCESS && aRemoteFiles.GetSize())
file_size = GetRemoteFileSize(aRemoteFiles[0].sFilePath);
 
CloseConnection();
return file_size;
}
GeneralProblem with multiple files uploadmemberdejalab27 Feb '06 - 10:17 
Hi Dan, Great application, i has been using it all weekend and i have some questions of things that happend to me, i´m not sure if is the same for everyone, so there are:
 
- When i try to upload multiple files, they just upload the first selected, this happen using the standar uploading window and when i drag and drop the files into the .exe icon too(at this way they don´t upload anyone).
- There are some kind of cookie?, i´m surprised but the window keep the username and dns information.
- Is not possible to me, up levels (to get other folders) to root in the download window
- Is the option for create folders in the server disable?
 
many thanks for your answer and for greater app.
Best regards
 
JR*
 
-- modified at 19:50 Monday 27th February, 2006
GeneralMemory Leakmembergvf31 Dec '05 - 1:27 
In CRemoteFile::SetFile, @ line 344 I added this:
}
progDlg.DestroyWindow();
}
 
CloseConnection();
Also in CRemoteFile::GetFile , @ line 232 I added this:
}
progDlg.DestroyWindow();
}
 
// cleanup
if (nRes != RMERR_SUCCESS && bTemp)

GeneralRe: Memory Leakmembergvf2 Jan '06 - 6:33 
I found also in http://www.codeproject.com/buglist/ftpfilefind.asp?msg=154600[^] the solucion to another problem:
 
In CRemoteFile::RemoteFileExists I've added a 'Close'
BOOL bFound = ff.FindFile(szRemotePath);
ff.Close();
if (bFound)
return TRUE;
 
In CRemoteFile::GetRemoteFileSize I've also added a 'Close'
DWORD dwFileSize = ff.GetLength();
ff.Close();
return dwFileSize;

GeneralGood Demomemberpetermxw6 Oct '05 - 23:50 
Thanks a lot!Smile | :)
GeneralProgress Dialog - ETAmemberMogwhy17 Aug '05 - 3:59 
It would be nice if the progress dialog had the additions of:
- Time Elapsed
- Time Remaining
- Percent as figures e.g. 90%
 
Great work, nicely done on the ToDoList project too.
 
Kind Regards,
Mogwhy
Generalinclude in c#membersides_dale15 Jun '05 - 16:03 
Is there a way to call this from a c# application?
Generalnothingmemberphyut24 May '05 - 22:44 
to view
Generalerror C2666 when building sample...memberMyron Belchmyer3 Dec '04 - 13:11 
I'm not a seasoned programmer so I'm not sure what this means. I'm using Visual Studio . NET 2003 and getting an error on lines 213 and 327 of enedit.cpp. I looked up the error but am not sophisticated enough to understand how to fix it. The error reads:
 
error C2666: 'CEnEdit::GetButtonRect' : 2 overloads have similar conversions
 
Here is what Microsoft has to say about this error. Can you please help? Thanks.
======================================================================================
 
Visual C++ Concepts: Building a C/C++ Program  
 
Compiler Error C2666'identifier' : number overloads have similar conversions
 
An overloaded function or operator is ambiguous.
 
Possible cause
 
Formal parameter lists are too similar to resolve ambiguity.
Possible solution
 
Explicitly cast one or more of the actual parameters.
The following sample generates C2666:
 
// C2666.cpp
struct complex
{
   complex(double);
};
 
void h(int,complex);
void h(double, double);
 
int main()
{
   h(3,4);   // C2666
}
This error can also be generated as a result of compiler conformance work that was done for Visual Studio .NET 2003: binary operators and user-defined conversions to pointer types.
 
For the binary operators <, >, <=, and >=, a passed parameter is now implicitly converted to the type of the operand if the parameter's type defines a user-defined conversion operator to convert to the type of the operand. There is now potential for ambiguity.
 
See Summary of Compile-Time Breaking Changes for more information.
 
For code that is valid in both the Visual Studio .NET 2003 and Visual Studio .NET versions of Visual C++, call the class operator explicitly using function syntax.
 
// C2666b.cpp
#include <string.h>
#include <stdio.h>
struct T
{
   T( const T& copy )
   {
         m_str = copy.m_str;
   }
 
   T( const char* str )
   {
         m_str = new char[strlen( str )+1];
         strcpy( m_str, str );
   }
 
   bool operator<( const T& RHS )
   {
         return m_str < RHS.m_str;
   }
 
   operator char*() const
   {
         return m_str;
   }
 
   char* m_str;
};
 
int main()
{
   T str1( "ABCD" );
   const char* str2 = "DEFG";
 
   // Error – Ambiguous call to operator<()
   // Trying to convert str1 to char* and then call
   // operator<( const char*, const char* )?
   //   OR
   // trying to convert str2 to T and then call
   // T::operator<( const T& )?
 
   if( str1 < str2 )   // C2666
   {
         printf("str1 < str2 \n");
   }
   // Try one of the following statements instead
   if ( str1.operator < ( str2 ) )   // Treat str2 as type T
   {
         printf("str1.operator < ( str2 )\n");
   }
 
   if ( str1.operator char*() < str2 )   // Treat str1 as type char*
   {
         printf("str1.operator char*() < str2\n");
   }
}
 

--------------------------------------------------------------------------------
 
Microsoft Product Support Knowledge Base Link
 
Send feedback on this topic to Microsoft
 
© Microsoft Corporation. All rights reserved.

 
Myron Belchmyer
GeneralRe: error C2666 when building sample...member.dan.g.5 Dec '04 - 23:35 
hi myron
 
i'm not quite sure how this crept in but i've updated the source code so could you re-download it and try again.
 
thanks
 
.dan.g.
 
AbstractSpoon Software
GeneralLooks great but I need to try it outmember^^o000o^^22 Nov '04 - 6:12 
It looks great but I need to try it out.
 
Thanks for all such good articles...
Smile | :)
 
CheersBlush | :O
GeneralReal great tool... Butmemberdiilbert22 Nov '04 - 5:58 
There is a problem. What if the FTP server is running on another port behind a firewall. It will need to be in passive mode for connections.
 
Is there any possiblity of this feature in the future.
 
Nice job, and by the way ToDoList keeps getting better and better Big Grin | :-D
 
-------
Removed... Too many questions Cool | :cool:
GeneralReal great tool... Butmemberdiilbert22 Nov '04 - 5:58 
There is a problem. What is the FTP server is running another port behind a firewall. It will need to be in passive mode for connections.
 
Is there any possiblity of this feature in the future.
 
Nice job, and by the way ToDoList keeps getting better and better Big Grin | :-D
 
-------
Removed... Too many questions Cool | :cool:
GeneralYes....memberxblahx21 Jul '05 - 5:53 
PASV mode support and a port option.... would make this 100% more useable for me. Smile | :)
 
Still lovin ToDoList, too, btw...
 
-xb
GeneralSlickmemberHockey25 Oct '04 - 13:57 
You got my five and a bookmark Smile | :)
 
Cheers to you!!!
 
How do I print my voice mail?
Generalnc doesn't workmemberdan_ds9 May '04 - 20:15 
hi dan,
 
the argument '/nc' doesn't appear to work for uploads, as the 'save as' dialog always appears (even if file exists).
 
cheers,
dan_ds
GeneralRe: nc doesn't workmember.dan.g.10 May '04 - 1:26 
hi dan,
 
i think the /nc switch relates only to confirmation of overwriting rather than the save as dialog.
 
to avoid the save as dialog i think you need to explicitly pass the full remote pathname to EasyFtp.
 
if this does not work or does not suit the way you want to use EasyFtp then let me know and i'll see what i can do.
 
rgds.
 
.dan.g.
 
AbstractSpoon
GeneralTimeoutmemberdan_ds6 Apr '04 - 16:10 
Hi Dan,
 
Is it possible to put a timeout setting in the app ?
While i was uploading a file, i lost connection to the net and the app locked up. I waited about 5 mins before killing the task. Would be nice if a default (hardcoded ?) timeout of about 120-180 seconds was implemented. Should be ample for those slower servers (or lost connections!).
 
Cheers, dan
GeneralRe: Timeoutmember.dan.g.6 Apr '04 - 20:56 
hi dan,
 
at present its coded all in the main thread which means that once its in a WinInet call there's not much to be done.
 
to implement a custom timeout would require me to put the download in a separate thread so that it could be terminated from the main thread.
 
unless there is a simpler solution?
 
rgds
 
.dan.g.
 
AbstractSpoon
QuestionMissing Command Line Option?membernet4ward6 Apr '04 - 4:20 
Is there a command line option to force updload in Binary mode or Ascii mode?
AnswerRe: Missing Command Line Option?member.dan.g.6 Apr '04 - 14:11 
not at present. currently its binary mode only.
 
however, it's a good idea and i'll add suitable switches to control it.
 
thanks
 
.dan.g.
 
AbstractSpoon
GeneralThe missing file prob fixed but...membertoadnan@hotmail.com28 Mar '04 - 20:11 
The file missing problem is fixed but the demo provided is different than the source...The demo also provides the option to logon anonymouse which is not present is source output.
 
The program allows to download files only, what about upload, will this be done in future relases
 
However, its nice, i like it, keep it up...
 
Thanx

 
Adnan
GeneralRe: The missing file prob fixed but...member.dan.g.28 Mar '04 - 23:48 
1. i just built the source without any problems (debug and release builds).
 
2. 'ReleaseGallot' is a private build which will not display the anonymous login.
 
3. you need to specify the -up commandline switch to do uploads as noted in the article text.
 
rgds
 
.dan.g.
 
AbstractSpoon
Generalthanks?!! :)membersurgeproof26 Mar '04 - 6:20 
you mean we can just build this into our own apps or modify it ourselves? great! thanks. haven't tried it yet but there you go! Wink | ;)
 
surgeproof
 
-------------------------------------------------------
Science without religion is lame, religion without science is blind. --Albert Einstein
The pioneers of a warless world are the youth who refuse military service. --Albert Einstein
GeneralRe: thanks?!! :)member.dan.g.28 Mar '04 - 23:49 
you're welcome Smile | :)
 
.dan.g.
 
AbstractSpoon

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 22 Mar 2004
Article Copyright 2004 by .dan.g.
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid