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

A Windows FTP Application

, 11 Feb 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
A fully functional FTP application for most Windows systems, inculding a Windows 7 specific built which addresses and uses the new features found in Windows 7!

Contents

Introduction

The purpose of this application is to create a fully functional FTP application that accomplishes most of the tasks professional FTP programs accomplish. The are two builds of this application:

  1. Windows 7-specific build: There is nothing different except that this application uses the Windows 7 features.
  2. All Windows systems-build: This build will work on most Windows systems (e.g.: XP/Vista). There is nothing different in this build, except that this build lacks Windows 7 features.

External libraries

This application uses the following libraries:

  1. An FTP client library for .NET 2.0.
  2. I decided to use this FTP library because it is well written and self explanatory. The author, Howard Richards, did a great job creating the library. However, the FTP library is missing some key features which are necessary for an FTP program. Therefore, I decided to modify the library. The following features have been added to this library:

    1. DownloadProgressChanged event with percentage
    2. DownloadCompleted event
    3. UploadProgressChanged event with percentage
    4. UploadCompleted event
    5. Changed some code and fixed a bug or two
    6. MessageReceived event - with COMMAND and RESPONSE techniques like FileZilla
    7. Raises event when a new message is received
    8. Cancel download
    9. Cancel upload
    10. Welcome message
  3. Enhanced BrowseForFolder styled TreeView
  4. This treeview, created by Chris Richner, displays all the directories in the file system in a treeview. In Win7 FTP, we will use this treeview for drag and drop operations. For example, dragging a file from the FTP sever and dropping it into this treeview will save the file to the path where the file was dropped.

  5. Windows API Code Pack for Microsoft .NET Framework
  6. Source code library that can be used to access some features of Windows 7 and Windows Vista from managed code.

*Note: All the library DLLs have been referenced in the Win7 FTP project. In case the references are missing, you can simply click on the appropriate library above and download it. For any other questions, you can post a message.

The whole deal about different builds

Well, you probably read the discussion on the bottom about the Windows XP/Vista version of this application. Someone suggested not making a version specific built, rather using if(CoreHelpers.RunningOnWin7) to run Windows specific features on a Windows 7 machine.

I was working on that; however, in this FTP application, there is a feature of Windows 7 called GlassForm, which displays the aero form. I use this feature for the Login form, Upload form, and the Download form. There is no way of running an application that displays a GlassForm. Even if you don't want the Aero feature. An error is thrown in any case. Also, in the UI, I am using a CommandLink, which is also part of the Windows API. That would not work on Windows XP.

So I created two builds: one that focuses on Windows 7 features and FTP, and the other that just focuses on Windows 7. Not a big deal to have two builds. If you want a Windows 7 build so you can explore Windows 7 features with FTP, you can get that. Else, you can just get the normal version.

What is so special about the Windows 7-specific build

As you all know, with Windows 7 was introduced some of the coolest libraries we have ever seen in the Windows API history. Well, to most developers, it is the coolest Microsoft has created for us. Usually, we have to do a lot ourselves, but the Windows API Code Pack does most of the things for us.

So I decided to use some of those features in this application. You will find the following features:

  1. The Aero Window: The Login form, Download form, and the Upload form use the Aero feature, which makes the form transparent.
  2. TaskBar: When download/upload progress changes, you can see the change in the taskbar.
  3. CommonOpenFile dialog: This is an advanced Open File dialog which has many new features and can also act as a FolderBrowse dialog.
  4. Command Link: I just added this to make the UI look good. It does nothing more than a button, however, it does look more professional.
  5. TaskDialog: This is displayed after a download has completed. It displays two options: Open File and Open Folder containing the file.

TaskBarManager.cs

I made the taskbar progress changing a little easier in the code by creating a new class called TaskBarManager. This class makes changing the progress easier, because it already has all the code setup. The code of the class follows:

public static void SetProgressValue(int Progress, int Maximum)
{
    //Declare State variable which is set to Normal (Green)
    TaskbarProgressBarState state = TaskbarProgressBarState.Normal;
    //Set the State
    TaskbarManager.Instance.SetProgressState(state);
    //Set value of the TaskBar progress
    TaskbarManager.Instance.SetProgressValue(Progress, Maximum);
}

public static void SetTaskBarProgressState(TaskbarProgressBarState state)
{
    //Set Status
    TaskbarManager.Instance.SetProgressState(state);
}
public static void ClearProgressValue()
{
    //Clear the progress, setting the state to NoProgress
    TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.NoProgress);
}

And I can call the code from the application, from any form, just like this:

//Change Progress
TaskBarManager.SetProgressValue(Progress, TotalProgress);

//Change State
HelperClasses.TaskBarManager.SetTaskBarProgressState(
  Microsoft.WindowsAPICodePack.Taskbar.TaskbarProgressBarState.Error);

Most Windows systems-build

This has nothing special like the Windows 7-specific build. This does the job of the FTP application in the same way as the Windows 7 build.

Application overview

This application contains the following forms (each will be discussed in detail).

  1. frmLogin.cs - Saves the user details, sets up and shows frmMain.
  2. frmMain.cs - Manages all the FTP operations and displays files and directories.
  3. frmRename.cs - Renames a file.
  4. frmNewFolder.cs - Creates a new folder.
  5. frmDownload.cs - Downloads a file, displays download information (progress, etc.).
  6. frmUpload.cs - Uploads a file, displays upload information (progress, etc.).

Log-in form - frmLogin

Win7Ftp_Login.jpg

Since our FTP client is stateless, we will only save the hostname, username, and password. This is how the frmLogin works:

try
{
    //Set FTPClient, and pass in the Hostname, Username, and Password.
    FTPclient objFtp = new FTPclient(txtHostName.Text, 
                           txtUserName.Text, txtPassword.Text);      
    //Set the Current Directory to "/" - Root Directory
    objFtp.CurrentDirectory = "/";
    Setup our frmMain variable
    frmMain Main = new frmMain();

    //SetFtpClient is a function in frmMain that sets the FtpClient.
    //I'll explain this function in more detail below.
    Main.SetFtpClient(objFtp);
    //Show MAIN form and HIDE this one
    Main.Show();
    //Hide this Form (frmLogin)
    this.Hide();
}
catch (Exception ex)
{
    //Display Error
    MessageBox.Show(ex.Message);
}

Main form - frmMain

This form is responsible for all the FTP actions that will take place in this program. The following tasks take place in frmMain:

  1. Double click navigation (like Windows): If you double click a folder, the folder is opened and all files and folders in it are shown in the listview. If you double click a file, then the user is prompted on whether he/she wants to save the file.
  2. Back button navigation: Clicking this will take the user a folder backwards. Nothing happens if we are at the root folder.
  3. Directory creation: The user can create a new directory.
  4. Rename file: The user can rename a file.
  5. Delete file/Directory: The user can delete a file.
  6. Download file: The user can select a location to save the file.
  7. Upload file: The user can select a file to upload to the current directory.
  8. Local file system navigation: The user can navigate to different folders in the file system using the treeview, or by entering the directory path in the textbox, or by opening the OpenFolder dialog, which automatically selects the folder in the treeview.
  9. Messages: When a message is sent, as a COMMAND, or received as a, RESPONSE, it is displayed in the listview with additional information, like date, message, status code, etc.

Most of these functions will be explained in more detail with code, in the FTP library explanation section of this article.

Let's look into SetFtpClient which we called in frmLogin. We only call this once.

public void SetFtpClient(Win7FTP.Library.FTPclient client)
{
    //Set FtpClient, the FtpClient Variable in this form, is set to client, from 
    //frmLogin. This is because the "client" already contains the information.
    FtpClient = client;

    //Display the Welcome Message
    Message = new ListViewItem();
    Message.Text = DateTime.Now.ToLongTimeString() + " " + 
                   DateTime.Now.ToLongDateString();
    Message.SubItems.Add("Welcome Message");
    Message.SubItems.Add(FtpClient.WelcomeMessage);
    Message.SubItems.Add("No Code");
    Message.SubItems.Add("/");
    //lstMessages is the ListView that contains 
    //all the Message. We want to display
    //the Welcome Message here as well.
    lstMessages.Items.Add(Message);

    //Setup OnMessageReceived Event. When a Message is sent/received, this event
    //fires and it is important to have this. Because it prompts the user on what
    //is happening in the background.
    FtpClient.OnNewMessageReceived += 
      new FTPclient.NewMessageHandler(FtpClient_OnNewMessageReceived);

    //Open and Display Root Directory ("/") and Files/Folders in it
    foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail("/"))
    {
        ListViewItem item = new ListViewItem();
        item.Text = folder.Filename;
        if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
            item.SubItems.Add("Folder");    //Its a Folder
        else
            item.SubItems.Add("File");      //Its a File

        item.SubItems.Add(folder.FullName);
        item.SubItems.Add(folder.Permission);
        item.SubItems.Add(folder.FileDateTime.ToShortTimeString() + 
                          folder.FileDateTime.ToShortDateString());
        item.SubItems.Add(GetFileSize(folder.Size));
        //lstRemoteSiteFiles is the ListView that displays all the Files and Folders
        //on the FTP Server
        lstRemoteSiteFiles.Items.Add(item);
    }
}

Important controls

  • lstRemoteSitesFiles - A ListView that displays all the files and folders in a directory on the FTP server.
  • tvFileSystem - A TreeView control from Chris Richner. Displays all the directories in the file system and helps in drag and drop.
  • lstMessages - A ListView that displays messages, like LIST for ListDirectoryDetail, which is a Command.

Rename form - frmRename

This form helps in renaming a file. We can only rename files; we cannot rename folders. Two important things about this form is the constructor and renaming the file.

Variables

string Path, Extension, FileName; //These will store the information, which will
                                  //will be required when we rename the file

frmMain ForMain;                  //I exactly don't remember why I chose to use 
                                  //frmMain, instead of just having a FTPClient, 
                                  //which I have in other Forms.

Constructor

public frmRename(string fileName, string CurrentDir, frmMain MainForm, string extension)
{
    //Set all the Variables
    Path = CurrentDir;     //assign Current Directory to Path, where the File that 
                           //we want to rename is located.
    Extension = extension; //Extension of the File we want to rename
    FileName = fileName;   //Name of the File we want to rename.
    ForMain = MainForm;    //Set the instance of frmMain
    
    InitializeComponent();
    
    //Aero Composition Event 
    AeroGlassCompositionChanged += 
      new AeroGlassCompositionChangedEvent(Form1_AeroGlassCompositionChanged);
    if (AeroGlassCompositionEnabled)
    {
        //We don't want pnlNonTransparent and the controls in it to be part of AERO
        //but we do want Aero Window...looks cool ;)
        ExcludeControlFromAeroGlass(pnlNonTransparent);
    }
    else
    {
        this.BackColor = Color.Teal;
    }

    //Set Information for User on Labels and Form Text
    this.Text = "Rename " + FileName;
    lblFileName.Text = "Filename: " + FileName;
    lblLocation.Text = "Location: " + Path;
}

Renaming the file

This renames the file to the new file's name.

ForMain.FtpClient.CurrentDirectory = Path;
//Set Current Directory

//FtpRename(Previous FileName, New FileName)
ForMain.FtpClient.FtpRename(FileName, txtRenameTo.Text);

New Folder form - frmNewFolder

This form is nothing but a dialog. When the new directory name is entered in the textbox and OK is clicked, DialogResult.OK is returned to frmMain.

The code works like this in frmMain:

//New instance of frmNewFolder
frmNewFolder NewFolderForm = new frmNewFolder();
if (NewFolderForm.ShowDialog() == DialogResult.OK)
{
    //Create New Directory
    FtpClient.FtpCreateDirectory(FtpClient.CurrentDirectory + 
                                 NewFolderForm.NewDirName);
    //Refresh Current Directory to view the newly created directory
    RefreshDirectory();
}

Refresh directory

RefreshDirectory() is a function in frmMain which I call when an operation like Upload File, Delete File, or Rename File occurs. The function basically reloads all the files and folders in the current directory into the lstRemoteSiteFiles in frmMain.

Download form - frmDownload

Win7Ftp_Downloading.jpg

This form manages the download information. When we are downloading a file, we now have two events that inform us on what is happening. These events were not in the original FTP Library, I manually implemented them.

What frmDownload manages

  1. Starting a download.
  2. Display progress, download percentage, and bytes downloaded.
  3. Show a task dialog when the download finishes. The task dialog has three options:
    1. Open file - Opens the file that was recently downloaded.
    2. Open folder containing the file - Open the folder that contains the file.
    3. Closes the task dialog and the form.
    4. Cancel the download.

Constructor - Starting the download

The constructor starts the download when the required arguments are passed in. The variables required are:

//String Variables we will need to use throughout the File.
string FileName, SaveFilePath, CurrentDirectory;

//FTPClient used to Download File and setup File Download Events
FTPclient FtpClient;

The constructor follows:

public frmDownload(string Filename, string Current_Directory, 
                   string SavePath, FTPclient Ftpclient)
{
    //Init Form
    InitializeComponent();

    //Setup Variables
    //Name of the File we want to download
    FileName = Filename;
    //Path where we want to save the Download
    SaveFilePath = SavePath;
    //Set the current Directory,
    //where the file we want to download is located.
    CurrentDirectory = Current_Directory;
    //ex: ftp://ftp.somesite.com/current_dir/File.exe
    lblDownloadFrom.Text = Ftpclient.Hostname + 
                           Current_Directory + FileName;
    lblSavePath.Text = SaveFilePath; //Label Text
    FtpClient = Ftpclient; //Set the FtpClient
    
    //Show Form
    this.Show();

    //Setup our Download Client and Start Downloading
    FtpClient.CurrentDirectory = Current_Directory;
    //OnProgressChanged Event
    FtpClient.OnDownloadProgressChanged += new 
      FTPclient.DownloadProgressChangedHandler(
      FtpClient_OnDownloadProgressChanged);
    //OnDownloadCompleted Event
    FtpClient.OnDownloadCompleted += new 
      FTPclient.DownloadCompletedHandler(FtpClient_OnDownloadCompleted);
    //Start the Download
    FtpClient.Download(FileName, SavePath, true);
}

OnDownloadCompleted - Fires when the download completes.

//Short Explanation on the Event
void FtpClient_OnDownloadCompleted(object sender, DownloadCompletedArgs e)
{
    if (e.DownloadCompleted)
    {
        //If an there is no error, then e.DownloadConpleted will be true.
        //Determining whether an error has occured or not, happens in the FTPclient
        //class, where this event is created.
        MessageBox.Show("Download Completed!");
    }
    else
    {
        //So here e.DownloadCompleted = false, meaning something went wrong.
        //That is why we have e.DownloadStatus, which displays the error message.
        MessageBox.SHow("Error: " + e.DownloadStatus);
    }
}

OnDownloadProgressChanged - Manages the progress of the download.

void FtpClient_OnDownloadProgressChanged(object sender, DownloadProgressChangedArgs e)
{
    //Set Value for Progressbar
    progressBar1.Maximum = Convert.ToInt32(e.TotleBytes);
    progressBar1.Value = Convert.ToInt32(e.BytesDownloaded);

    // Calculate the download progress in percentages
    Int64 PercentProgress = 
      Convert.ToInt64((progressBar1.Value * 100) / e.TotleBytes);

    //e.TotalBytes is the TotalBytes to Download
    //e.BytesDownloaded is the bytes already downloaded 
}

Canceling a download

To cancel a download, simply call FtpClient.CancelDownload(). I created this to use if the user wants to cancel a download. This function does a verification before performing anything, and deletes the the download since it is not completed.

Upload form - frmUpload

This form manages the upload file information. When we upload a file, we now have two events that inform us on what is happening. These events were not in the original FTP Library, I manually implemented them.

What frmUpload manages

  1. Start uploading the file
  2. Display upload progress, upload percentage, and bytes uploaded/total bytes.
  3. Display message box when upload process finishes.
  4. Cancel an upload.

Constructor - Start uploading

The constructor starts uploading the file when it is called. The variables required are:

//Variable that will hold the name of the File we are uploading. ex: File.txt
string FileName;

//FTPclient that will be used to Upload the File and manage all the events
FTPclient FtpClient;

The constructor:

public frmUpload(string UploadFilePath, string UploadDirectory, FTPclient Ftpclient)
{
    InitializeComponent();

    //Setup Variables
    //FileName without Directory. ex: FileName.txt
    FileName = System.IO.Path.GetFileName(UploadFilePath);
    FtpClient = Ftpclient; //Set the FtpClient

    //Show Form
    this.Show();

    //Setup our Download Client and Start Downloading
    FtpClient.CurrentDirectory = UploadDirectory;
    FtpClient.OnUploadCompleted += new 
      FTPclient.UploadCompletedHandler(FtpClient_OnUploadCompleted);
    FtpClient.OnUploadProgressChanged += new 
      FTPclient.UploadProgressChangedHandler(FtpClient_OnUploadProgressChanged);
    FtpClient.Upload(UploadFilePath, UploadDirectory + FileName);
}

Upload events

OnUploadProgressChanges - Fired when the progress of the upload changes.

void FtpClient_OnUploadProgressChanged(object sender, UploadProgressChangedArgs e)
{
    //Set Value and Maximum for Progressbar
    progressBar1.Maximum = Convert.ToInt32(e.TotleBytes);
    progressBar1.Value = Convert.ToInt32(e.BytesUploaded);

    //Calculate the Download Progress in Percentage
    Int64 PercentProgress = Convert.ToInt64((e.BytesUploaded * 100) / e.TotleBytes);

    //e.BytesUploaded tells us the amount of Bytes Uploaded
    //e.TotalBytes tells us the TotalBytes to Upload.
}

OnUploadComplete - Fires when the file is uploaded.

if (e.UploadCompleted)
{
    //If an there is no error, then e.UploadCompleted will be true.
    //Determining whether an error has occured or not, happens in the FTPclient
    //class, where this event is created.
    MessageBox.Show("Upload Completed!");  
}
else
{
    //So here e.DownloadCompleted = false, meaning something went wrong.
    //That is why we have e.DownloadStatus, which displays the error message.
    MessageBox.Show("Error: " + e.UploadStatus);
}

Canceling an upload

To cancel an upload, simply call FtpClient.CancelUpload(). I created for using if the user wants to cancel an upload. This function does a verification before performing anything, and deletes the upload on the server since it is incomplete.

FTP Library functions

As I told you, I made many changes to this library to meet the needs of this application. Let me explain to you each important function and what it does and how to use it.

FtpClient.FtpCreateDirectory

This creates a new directory.

//You must address the whole path of the New Direcory. 
//For example: "/CurrentDirectory/" + "New Directory"
FtpClient.FtpCreateDirectory(CurrentDirectory + NewDirectoryName);

FtpClient.FtpRename

This renames a file. *Note: This only applies to files, you cannot rename folders.

//It is recomended that you set the CurrentDirectory to the Directory that contains
//the file you want to rename, if you haven't
FtpClient.CurrentDirectory = "/Directory/";

//You must pass in the Old File Name and the New File Name
FtpClient.FtpRename("OldFileName.txt", "NewFileName.txt");

FtpClient.FtpDelete

This method will allow you to delete a file.

//It is recomended that you set the CurrentDirectory to the Directory that contains
//the file you want to rename, if you haven't
FtpClient.CurrentDirectory = "/Directory/";

//Delete the FILE, by passing in the name of the File you want to Delete.
FtpClient.FtpDelete(FileName);

FtpClient.FtpDeleteDirectory

This method will allow you to delete a directory.

//It is recomended that you set the CurrentDirectory to the Directory that contains
//the file you want to rename, if you haven't
FtpClient.CurrentDirectory = "/Directory/";

//Delete the FOLDER
FtpClient.FtpDeleteDirectory(lstRemoteSiteFiles.SelectedItems[0].SubItems[2].Text);

FtpClient.Download

This method will allow you to download a file from the server.

//It is recomended that you set the CurrentDirectory to the Directory that contains
//the file you want to rename, if you haven't
FtpClient.CurrentDirectory = "/Directory/";

//FileName = Name of the file to download
//SavePath = Path, including FileName, where the File will be saved.
//true or false - true, if you want to Overwrite file, if it already exists.
FtpClient.Download(FileName, SavePath, true);

FtpClient.Upload

This method will upload a file to the server.

//UploadFilePath = Full Path of the File that you want to Upload
//UploadDirectory = CurrentDirectory, where you want to upload the file
//FileName = Name of the Uploaded File on the Server.
FtpClient.Upload(UploadFilePath, UploadDirectory + FileName);

FtpClient.ListDirectoryDetail

This method grabs all the folders and files in a directory and displays all their information.

foreach (FTPfileInfo folder in FtpClient.ListDirectoryDetail(txtRemoteDirectory.Text))
{
    folder.Filename;   //Returns Folder/FileName Name
    if (folder.FileType == FTPfileInfo.DirectoryEntryTypes.Directory)
    //Tells if its a Folder or a File
        //Its a Folder
    else
        //Its a File

    folder.FullName;   //Returns FullPath of the Folder/File
    folder.Permission; //Permissions regarding Folder/File
    //Returns the DateandTime of creation/modification of the folder/file
    folder.FileDateTime.ToShortTimeString() + folder.FileDateTime.ToShortDateString();
    item.SubItems.Add(GetFileSize(folder.Size));  //Returns Size of the Folder/File
}

Conclusion

I achieved my goal and created a fully functional FTP program. It is not the best, I am going to update it in the future to make it better. If you know of a way to improve this application, then comments/suggestions are welcome. I created this application in a week and had a lot of issues with bugs. So I won't say it is perfect. But thanks for hanging by and giving the program a try.

Future updates

Future releases of this application will have the following features, plus more!

  1. Download multiple files
  2. Upload multiple files
  3. Download folders and zipped files
  4. Keep track of all FTP sites, user names, and passwords
  5. Create a custom JumpList and show FTP sites there, so when the user clicks on an FTP site, a new instance of Win7 FTP will open the FTP site

For users not running Windows 7, I will post another article which will support most Windows systems.

Updates

Revision 2/9/2010

  • Added a new build which supports most modern Windows PCs.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

harsimranb
Software Developer
United States United States
I write code.

Comments and Discussions

 
QuestionDownloading a directory with its sub-directories. PinmemberMember 949949719-May-14 7:28 
QuestionSeucre FTP PinmemberOliverLan18-Mar-13 14:54 
AnswerRe: Seucre FTP Pinmemberharsimranb19-Mar-13 9:53 
QuestionUnable to parse line error Pinmemberbisewski2-Nov-12 7:40 
AnswerRe: Unable to parse line error PinmemberPathachiever7-Dec-12 7:01 
QuestionType Mismatch Pinmemberudnsofyan18-Apr-12 17:47 
AnswerRe: Type Mismatch PinmemberPathachiever7-Dec-12 6:59 
Questionwinxp download package seems not correct PinmemberAdamSteven15-Apr-12 0:21 
AnswerRe: winxp download package seems not correct PinmemberPathachiever7-Dec-12 6:55 
QuestionWhy show dialog ? [modified] Pinmemberthanhluan71011-Mar-12 1:35 
AnswerRe: Why show dialog ? PinmemberPathachiever7-Dec-12 7:03 
GeneralAbout New Version! Pinmembersunboylyl16-Mar-11 6:02 
GeneralRe: About New Version! PinmemberPathachiever6-Jun-11 15:09 
GeneralDirectory exits ? [modified] PinmemberSaNoooJ24-Sep-10 6:45 
GeneralRe: Directory exits ? PinmemberPathachiever6-Jun-11 15:12 
QuestionError Uploading :::: Error: Object reference not set to an instance of an object. Why ? PinmemberakZ3us10-Aug-10 10:51 
AnswerRe: Error Uploading :::: Error: Object reference not set to an instance of an object. Why ? Pinmembermygame11-Aug-10 17:08 
GeneralRe: Error Uploading :::: Error: Object reference not set to an instance of an object. Why ? PinmemberSteve565413-Feb-11 12:31 
GeneralRe: Error Uploading :::: Error: Object reference not set to an instance of an object. Why ? PinmemberPathachiever7-Dec-12 7:04 
QuestionLong URL's not supported? PinmembertheRealScarecrow4-Aug-10 11:22 
AnswerRe: Long URL's not supported? PinmemberPathachiever7-Aug-10 6:18 
QuestionIs there a Visual Basic version? PinmemberGrahamEd2-Aug-10 3:01 
AnswerRe: Is there a Visual Basic version? PinmemberPathachiever2-Aug-10 17:55 
AnswerRe: Is there a Visual Basic version? PinmemberPathachiever2-Aug-10 18:01 
GeneralRe: Is there a Visual Basic version? PinmemberGrahamEd3-Aug-10 23:45 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141216.1 | Last Updated 11 Feb 2010
Article Copyright 2010 by harsimranb
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid