Thursday, April 18, 2013

Some Windows Forms magic in .NET

1. Multithreading support – While there are many other excellent features of the language, multithreading support is what tops my list. The reason is that the threading mechanism is so much intuitive and easier to implement than many other languages like C++ or even java.
What other language allows you to start a thread, then pause it for 5 seconds, then wait for 7 seconds for it to complete, then instantly terminate it if it doesn't complete and implement this in just 4 lines of code!

Other multithreading features like mutex, lock, Monitor and Event are just as intuitive to use. The end result is that even the average programmer who doesn't have an iron grip over thread programming ends up coding a pretty decent multithreaded solution in C#.


2. Rich Framework Library – Though theoretically C# is a language in its own right, it is almost inseparable with the .NET Framework that it is so closely integrated with. Yet another reason I prefer C# and .NET so much is that it comes pre-bundled with such a comprehensive library (Framework Class Library), that you hardly ever need to look elsewhere to implement any feature you want – be it anything:
  1. Networking/Socket programming (System.Net and System.Net.Sockets)
  2. File I/O (System.IO)
  3. Graphics (System.Drawing)
  4. Multithreading (System.Threading)
  5. Remoting (System.Runtime.Remoting)
  6. Database interaction (System.Data, System.Data.SqlClient)
    Moreover, the library integrates so well with Windows environment that you never have to worry about performance as it happens in case of Java. You can concentrate entirely on writing your business-logic without worrying about the underlying low-level plumbing of these things which .NET does seamlessly for you.
3. Elegance in language – Especially for someone who admires the compactness and preciseness of the C family of languages and at the same time, is also familiar with the rapid development cycles of Visual Basic language, C# offers an excellent blend of the two worlds. In fact, this was the very purpose when C# was initially designed in 1999. To bring the elegant syntax of C++ to VB programmers, and to bring the RAD nature of VB to C++.


4. Delegates – Though not many people are very fond of this feature, in my humble opinion, the language allows you to do almost everything you can do with pointers in C/C++ without the corresponding risk associated with referencing/dereferencing with pointers. With delegates, you can define a simple prototype for a function, and then use it as a custom datatype that points to any actual function that matches the prototype.



5. Automatic memory management: Though it is not a feature of C# language per se, I cannot overstate its importance nevertheless. I still remember how tedious it is to manage memory in C language using malloc, realloc and dealloc from my college days. Though the situation improved with Visual Basic, the solution wasn't quite robust since each VB program ran in its own unmanaged process and any loopholes in a single part of your program can bring the whole thing crashing down. Such things no longer happen in C#. The CLR takes care of allocating memory to your objects and there is a garbage-collector which automatically disposes any objects you forgot to set as null. So graceful!! (Though a caveat is that this grace isn't quite available when dealing with COM components and you have to manually call Marshal.ReleaseComObject() to dispose your COM objects, but thats another story).

6. Networking, Sockets and Stuff: At work, I have to deal with several networking projects that typically involve socket programming – sending/receiving a bunch of raw binary data on specific ports using TCP/UDP sockets. I can never imagine the situation if there were no C# to help by providing its feature-filled classes in System.Net and System.Net.Sockets namespaces that do the job seamlessly. Here are some of the classes that I frequently use:

    1. HttpWebRequest - An easy to use wrapper that handles all the low level plumbing required to create an Http web request. All you have to provide is the url as input.

    2. HttpWebResponse - Once the request is created, calling GetReponse() on the request object will return HttpWebResponse which is equally helpful. This object has GetResponseStream() which gives a NetworkStream object from which we can seamlessly read the received data in whatever format we like viz. raw-bytes,  strings, xml, etc.

    3. TcpClient, TcpServer, Socket - Sometimes, the scenario is not as simple as sending a simple web request and reading the response. If you want to handle all the low level details yourself, then these three classes will be the most helpful to you.

Lately, I'm working on an opensource project called scavenger, an internet download manager coded in C#. I've made extensive use of all these classes in that. 


7. WinForms, WPF and Stuff: Using WinForms is a breeze if you have ever developed anything in Visual Basic 6 or a similar tool. The most useful thing about WinForms is its rich set of .NET controls ranging from TreeViews, ListViews, Progressbars, Toolbars, Split containers, tabbed containers, layout panels – you name it. GUI development was never that easier. I haven't used WPF quite, but from what I've heard, I surmise that it must be same there as well.

Tuesday, April 16, 2013

7 Reasons why I like the C# programming language

1. Multithreading support – While there are many other excellent features of the language, multithreading support is what tops my list. The reason is that the threading mechanism is so much intuitive and easier to implement than many other languages like C++ or even java.
What other language allows you to start a thread, then pause it for 5 seconds, then wait for 7 seconds for it to complete, then instantly terminate it if it doesn't complete and implement this in just 4 lines of code!

private void startThread()
{
    Thread fooThread = new Thread(foo);
    fooThread.Start(); Thread.Sleep(5000); fooThread.Suspend();
    fooThread.Join(7000);
    if (fooThread.IsAlive) fooThread.Abort(); 
}


Other multithreading features like mutex, lock, Monitor and Event are just as intuitive to use. The end result is that even the average programmer who doesn't have an iron grip over thread programming ends up coding a pretty decent multithreaded solution in C#.


2. Rich Framework Library – Though theoretically C# is a language in its own right, it is almost inseparable with the .NET Framework that it is so closely integrated with. Yet another reason I prefer C# and .NET so much is that it comes pre-bundled with such a comprehensive library (Framework Class Library), that you hardly ever need to look elsewhere to implement any feature you want – be it anything:
  1. Networking/Socket programming (System.Net and System.Net.Sockets)
  2. File I/O (System.IO)
  3. Graphics (System.Drawing)
  4. Multithreading (System.Threading)
  5. Remoting (System.Runtime.Remoting)
  6. Database interaction (System.Data, System.Data.SqlClient)
    Moreover, the library integrates so well with Windows environment that you never have to worry about performance as it happens in case of Java. You can concentrate entirely on writing your business-logic without worrying about the underlying low-level plumbing of these things which .NET does seamlessly for you.
3. Elegance in language – Especially for someone who admires the compactness and preciseness of the C family of languages and at the same time, is also familiar with the rapid development cycles of Visual Basic language, C# offers an excellent blend of the two worlds. In fact, this was the very purpose when C# was initially designed in 1999. To bring the elegant syntax of C++ to VB programmers, and to bring the RAD nature of VB to C++.


4. Delegates – Though not many people are very fond of this feature, in my humble opinion, the language allows you to do almost everything you can do with pointers in C/C++ without the corresponding risk associated with referencing/dereferencing with pointers. With delegates, you can define a simple prototype for a function, and then use it as a custom datatype that points to any actual function that matches the prototype.


delegate void somedelegate(int a, int b);

public static void foo(int x,int y)
{
return;
}

public static void main()
{
somedelegate f = new somedelegate(foo); //f now contains a reference to function foo
}

5. Automatic memory management: Though it is not a feature of C# language per se, I cannot overstate its importance nevertheless. I still remember how tedious it is to manage memory in C language using malloc, realloc and dealloc from my college days. Though the situation improved with Visual Basic, the solution wasn't quite robust since each VB program ran in its own unmanaged process and any loopholes in a single part of your program can bring the whole thing crashing down. Such things no longer happen in C#. The CLR takes care of allocating memory to your objects and there is a garbage-collector which automatically disposes any objects you forgot to set as null. So graceful!! (Though a caveat is that this grace isn't quite available when dealing with COM components and you have to manually call Marshal.ReleaseComObject() to dispose your COM objects, but thats another story).

6. Networking, Sockets and Stuff: At work, I have to deal with several networking projects that typically involve socket programming – sending/receiving a bunch of raw binary data on specific ports using TCP/UDP sockets. I can never imagine the situation if there were no C# to help by providing its feature-filled classes in System.Net and System.Net.Sockets namespaces that do the job seamlessly. Here are some of the classes that I frequently use:

    1. HttpWebRequest - An easy to use wrapper that handles all the low level plumbing required to create an Http web request. All you have to provide is the url as input. 


    2. HttpWebResponse - Once the request is created, calling GetReponse() on the request object will return HttpWebResponse which is equally helpful. This object has GetResponseStream() which gives a NetworkStream object from which we can seamlessly read the received data in whatever format we like viz. raw-bytes,  strings, xml, etc.

    3. TcpClient, TcpServer, Socket - Sometimes, the scenario is not as simple as sending a simple web request and reading the response. If you want to handle all the low level details yourself, then these three classes will be the most helpful to you.

Lately, I'm working on an opensource project called scavenger, an internet download manager coded in C#. I've made extensive use of all these classes in that. 


7. WinForms, WPF and Stuff: Using WinForms is a breeze if you have ever developed anything in Visual Basic 6 or a similar tool. The most useful thing about WinForms is its rich set of .NET controls ranging from TreeViews, ListViews, Progressbars, Toolbars, Split containers, tabbed containers, layout panels – you name it. GUI development was never that easier. I haven't used WPF quite, but from what I've heard, I surmise that it must be same there as well.

Sunday, February 10, 2013

Some VB6 Tricks

-->
Though Visual Basic 6 has started getting lost in antiquity since the advent of .NET, we do know there are still zillions of VB6 programs in existence, with medium to high complexity. They are not migrated to C# or VB.NET and are maintained in their current state.
This may be due to several reasons, the primary being the high cost involved in migrating to .NET platform. Given below are a few tips and tricks to better the user experience that I’ve come across during my programming endeavors while dealing with VB6:
[1] Adding horizontal scrollbar to a list box: The standard listbox control provided by VB6 pretty much serves our purpose when we want to show a list of possible values to a user from which she can select one. However, there is one slight glitch: There is no horizontal scrollbar in it. If the number of list items increase beyond the visible area of the listbox control, then yes, we automatically get a vertical scrollbar to scroll. But when the text width is too much, the user cannot read the entire text, you get something like this:






In the above screen there is a vertical, but no horizontal bar. To overcome this limitation, we need to use a Windows API function called SendMessage(). Windows API is a powerful method to get access to functionality that VB6 does not provide out of the box. In order to use the SendMessage() function, all you have to do is declare this function at the top of your VB Form code:

Option Explicit
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, ByVal _
wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Const LB_SETHORIZONTALEXTENT = &H194


Do remember that you only need to declare this once in your form, though this function may be called at several places. If you are going to use the function at several places, then declare it in a global module instead and make it public. The second declaration beginning with “Const” declares a constant that comes handy while using this function. Now, let us use this function by calling it. Typically, this will be inside the Form_Load event of your form:
Dim x As Long
Dim s As String
x = TextWidth(List1.List(0) & " ")
If ScaleMode = vbTwips Then _
x = x / Screen.TwipsPerPixelX ' if twips change to pixels
SendMessage List1.hwnd, LB_SETHORIZONTALEXTENT, x, 0

Here, we first determine the width our horizontal scrollbar will have. This is determined by the variable x. We assign it the text-width of the first item in your listbox i.e. List1.List(0). In a real world application however, you have to make it equal to the widest string in your listbox. Once you do this, you will have a horizontal scrollbar in your listbox as shown below:







[2] Adding soft-search facility to a listbox: Soft-search is a facility provided by many applications to instantly show filtered results in a dropdown as you type. Popular example of this is the google search box that shows matching search terms in a dropdown as you start typing your search text. Now, suppose, you want to provide a similar facility in your VB6 

Form by providing a textbox control to type and a listbox to filter the soft-search results. How difficult do you think this would be? Pretty trivial, I would say, by using the SendMessage() API function. You already get what the user is typing in the textbox in the Change() event. All you have to do is call this API function, and pass the search string and list-box handle as the parameters.

The API will automatically find and return the index of the searched string if found in the Listbox!! Now all you have to do is set the topindex property of the listbox to that of the value returned by SendMessage() function:


Private Sub Text1_Change()
Dim i As Integer
i = SendMessage(List1.hwnd, LB_FINDSTRING, -1, ByVal Text1.Text)
If i <> -1 Then
List1.TopIndex = i
'Else
'List1.Selected(
End If
End Sub



Sunday, February 5, 2012

How to convert an image to bytes in .NET?

One of the most standard queries I come across in many of the coding forums these days is, how do we convert an image (Image/Bitmap class) in .NET to a byte[] array? The answer to this is very straight forward - a few lines of code in VB.NET or C#:


VB.NET:


        Private Function CaptureScreen() As Bitmap
            'CAPTURE THE BITMAP
            ' Size size is how big an area to capture
            ' pointOrigin is the upper left corner of the area to capture
            Dim width As Integer =  Screen.PrimaryScreen.Bounds.X + Screen.PrimaryScreen.Bounds.Width
            Dim height As Integer =  Screen.PrimaryScreen.Bounds.Y + Screen.PrimaryScreen.Bounds.Height
            Dim size As Size =  New Size(width,height)
            Dim pointOfOrigin As Point =  New Point(0,0)
            Dim desktopBitmap As Bitmap =  New Bitmap(size.Width,size.Height)
            Imports (Graphics graphics = Graphics.FromImage(desktopBitmap))
            {
                graphics.CopyFromScreen(pointOfOrigin,New Point(0,0),size)
            }
            'CAPTURE CURSOR
            Dim cursorX As Integer = 0,cursorY As Integer =  0
            Dim cursorBitmap As Bitmap =  CaptureCursor( cursorX,ref cursorY)
            'MERGE THE CURSOR INTO DESKTOP BITMAP
            If Not cursorBitmap Is Nothing Then
                Dim g As Graphics
                Dim r As Rectangle
                r = New Rectangle(cursorX, cursorY, cursorBitmap.Width, cursorBitmap.Height)
                g = Graphics.FromImage(desktopBitmap)
                g.DrawImage(cursorBitmap, r)
                g.Flush()
                Return desktopBitmap
            Else
                Return desktopBitmap
            End If
        End Function


C#: 


        private Bitmap CaptureScreen()
        {
            //CAPTURE THE BITMAP
            // Size size is how big an area to capture
            // pointOrigin is the upper left corner of the area to capture
            int width = Screen.PrimaryScreen.Bounds.X + Screen.PrimaryScreen.Bounds.Width;
            int height = Screen.PrimaryScreen.Bounds.Y + Screen.PrimaryScreen.Bounds.Height;
            Size size = new Size(width, height);
            Point pointOfOrigin = new Point(0, 0);
            Bitmap desktopBitmap = new Bitmap(size.Width, size.Height);
            using (Graphics graphics = Graphics.FromImage(desktopBitmap))
            {
                graphics.CopyFromScreen(pointOfOrigin, new Point(0, 0), size);
            }
            //CAPTURE CURSOR
            int cursorX=0, cursorY=0;
            Bitmap cursorBitmap = CaptureCursor(ref cursorX,ref cursorY);
            //MERGE THE CURSOR INTO DESKTOP BITMAP
            if (cursorBitmap != null)
            {
                Graphics g;
                Rectangle r;
                r = new Rectangle(cursorX, cursorY, cursorBitmap.Width, cursorBitmap.Height);
                g = Graphics.FromImage(desktopBitmap);
                g.DrawImage(cursorBitmap, r);
                g.Flush();
                return desktopBitmap;
            }
            else
            {
                return desktopBitmap;
            }
        }




Do note that the parameter passed to this function should be an object of System.Drawing.Bitmap type. If you have an object of Image type instead, you may convert it to Bitmap by doing this:


Graphics.FromImage(imageObject)

Tuesday, January 17, 2012

How to code efficiently in a .NET language?

Here are some techniques you may apply in your quest to become a better .NET coder:

[1] Leverage the power of industry-standard tools. There exist many proven tools to help you with various programming needs.

Some, like the the Redgate reflector is a commercial one (with a limited-feature free trial version available). It is used to reconstruct the lost source code (in VB.NET/C#) from the .NET assembly (exe/dll).

On the other hand, a NUnit (used for unit testing .NET components) and NANT (build tool to automate build process of .NET sources) are opensource and 100% free. A fairly comprehensive list of all such tools are available here:

List of free and opensource .NET tools.



[2] Follow proper naming conventions for variables and constants. A good naming convention has several advantages such as providing meta-data about the variable or function name, promotes consistency and readability within a team and provides better understanding in case of code-reuse.
For variables and type names, Microsoft recommends a pascal casing convention where the first letter of the name is capitalized and the rest is in proper case (example "ToString", "Red", "BackColor", "ForeColor", etc.). For parameter names, Microsoft recommends camel casing convention where the first letter of the name is small and the rest is proper case (example "toString", "red", "backColor", "foreColor", etc.)

Microsoft also has recommendations for naming Assemblies & DLLs,  Namespaces, Struct Types, etc. For more information on this, see Microsoft .NET Design guidelines for class libraries

[3] Always keep possible code-reuse in mind while coding. While coding, it is always a good practice to consider the effect of exposing your functionality to other users in the form of a Library/API. Instead of scavenging for bugs later, you will save lots of time and concentration by planning ahead for it.

It is also a good practice to avoid possible formatting of data while returning values from your functions or sub-procedures, and leave those implementation details to the caller instead.

[4] Clean up your unused and local variables. This is the number one efficient factor that directly affects the performance of your code. Always keep a habit of releasing the memory used by local variables in the Finally block. Also, release all .NET and COM Global/Module-level variables when they are no longer needed.

In order to clear COM objects, you have to call Marshal.ReleaseCOMObject() function explicitly, whereas .NET objects will be released by just setting them to null (C#) or Nothing (VB.NET).

[5] Avoid using GoTo statements. There is nothing inherently wrong with using Goto statements in VB.NET, but they reduce the code-readability. Its easy to lose track of the issue at hand, while scavenging for the possible effects by following your Goto statements.

[6] Always use FxCop to audit your code. FxCop is a free tool from Microsoft that checks your assembly for compliance with Microsoft Design guidelines.

Apart from highlighting inconsistencies in issues like naming-conventions, an important advantage of using FxCop is that it brings to light several performance improvizations that could be made to your code. Here is the download page for FxCop version 10.0:

FxCop download page.

Saturday, August 6, 2011

How to perform Cross-thread communication in .NET programs

Multithreading is a quite useful technique in programming, especially in complex applications that seem to do a lot of things at the same time. The System.Threading class in .NET provides members that allow us to seamlessly create, stop and abort threads at will. But this article is not about managing threads, there are already several texts available for that. This is about managing a very typical scenario that is faced by a developer working on a multi threaded application.

Quite recently, while developing a network application and using multiple threads, I came across this very problem. The program was basically a TCP Message Server that accepted TCP and UDP requests on the network and replied to them with some processed data. We had one main GUI that acts as the user interface for the server. Now, at the click of a start button, there are two different threads that need to start: a TCPListener and a UDPListener thread. So now, we had three threads:-
  1. The main GUI thread started by the user.
  2. TCPListener thread listening for TCP requests on a port.
  3. UDPListener thread listening for UDP requests on a different port.
Here are some parts of the implementation:
GUI: Basic Server GUI with a Start/Stop button and a text box for last message received.

Saturday, July 30, 2011

How to create an FTP client in VB.NET

The FTP (File Transfer Protocol) is one of the oldest and most popular ways of transferring files from one computer to another over a TCP network such as the internet. It is a Client/Server based protocol based on cear-text authentication. To get a detailed idea of what FTP is and how it is used, refer to http://en.wikipedia.org/wiki/File_Transfer_Protocol

In .NET,  we implement the FTP functionality using the System.Net namespace. This is a comprehensive namespace which encapsulates functionality to perform various network tasks. These include FTP related tasks like connecting to an FTP server and listing its directory.

In this article, we will learn how to create an FTP Client using the VB.NET language right from scratch.

The IDE I have used is Visual Studio 2008, though you can easily port it to the 2010 version. The complete source-code for this solution is available on Google Code. You can download it here:
 
http://code.google.com/p/ftpexplorer/downloads/detail?name=ftpexplorer_source_1.zip

You can also translate it to C# (with a little bit of effort) since all .NET languages share the same FCL and CLI. There is a C# equivalent for each syntax.

To begin, create a VB solution of the type “Windows Forms Application”. Add a Form to it, then add the below controls to the Form:

  1. A TreeView control – to browse the local file system
  2. A ListView control – to browse the remote ftp structure
  3. A TextBox and a Button to type Url and connect to the FTP server
  4. Two Upload and Download buttons
  5. A multi-line TextBox for logging details
  6. A StatusStrip control with a label on it (Optional)
This will be your FTP client interface where you can do things like connecting to a remote ftp site using your username and password and start uploading/downloading files. The appearance is quite minimalist, and I have abstained from adding many advanced functions like using an SSL connection and applying cryptography, so as not to overwhelm the learners. Here is our little FTP Explorer in action:






The Upload button uploads the selected file on the local system to the remote directory that is currently selected. Similarly, selecting a file on the remote system and clicking the download button downloads the file to the selected local folder.

On the remote system, double-clicking a folder will navigate to that folder. The big multi-line textbox is for logging the ftp events.

On the coding front, I have abstracted the core FTP related functionality in a different class called FtpClient, so that the functionality could be reused or exposed through an API.

The local-system's explorer-tree on the top left side is just filled with the drive letters in the beginning. Later, as the user starts expanding the nodes, they are populated with the sub-folders and files.

Private Sub tvwLocal_AfterExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles tvwLocal.AfterExpand
On Error GoTo em
Dim current As TreeNode = e.Node
'Dim nextFile As String = Dir(current.Name & "\", FileAttribute.Directory)
Dim dirInfo As String() = Directory.GetDirectories(current.Name & "\")
current.Nodes.Clear()
'Do While (nextFile IsNot Nothing AndAlso nextFile.Length > 0)
For Each nextFile As String In dirInfo
Dim dirnode As New TreeNode
dirnode.Text = ExtractFileName(nextFile)
dirnode.Name = nextFile ' current.Name & "\" & nextFile
dirnode.ImageIndex = Images.CLOSED_FOLDER
dirnode.SelectedImageIndex = Images.CLOSED_FOLDER
dirnode.Nodes.Add("*DUMMY*")
'current.Nodes.Add(current.Name & "\" & nextFile, nextFile, Images.CLOSED_FOLDER, Images.CLOSED_FOLDER)
current.Nodes.Add(dirnode)
'Loop
Next
dirInfo = Directory.GetFiles(current.Name & "\")
'nextFile = Dir(current.Name & "\")
For Each nextFile As String In dirInfo
current.Nodes.Add(nextFile, ExtractFileName(nextFile), Images.FILE, Images.FILE)
Next
Exit Sub
em:
If Err.Number <> 52 And Err.Number <> 57 Then
MessageBox.Show(Err.Description)
End If
End Sub

As for the FTP handling, the class constructor takes three arguments: the FTP host, username and password. The most important method in this class is the ListDirectory(). This function sends a LIST request to the remote ftp server and gets the directory and files listing in the form of an ftp-string. It then creates an object of FtpDirectory class which is basically a generic list of FtpFileInfo objects. FtpFileInfo is an important object that reads the ftp-string using regular expressions and categorizes them into a file or a folder.




Public Function ListDirectory(Optional ByVal directory As String = "") As FtpDirectory
On Error GoTo em
Dim url As String
If directory.Length = 0 Then
Me.CurrentDirectory = "/"
'url = Hostname
ElseIf directory = "." Then
'No need to do anything
ElseIf directory = ".." Then
If CurrentDirectory <> "/" Then
'/pub/a
Dim index As Integer = Me.CurrentDirectory.LastIndexOf("/")
CurrentDirectory = CurrentDirectory.Substring(0, index)
If CurrentDirectory.Length = 0 Then CurrentDirectory = "/"
Else
RaiseEvent StatusChanged("Already in the root directory")
'url = Hostname & "/" & CurrentDirectory
End If
Else
Me.CurrentDirectory &= IIf(CurrentDirectory.Length = 1, "", "/") & directory
End If
url = GetCurrentUrl()
RaiseEvent StatusChanged("Logging in with user " & Username)
'return a simple list of filenames in directory
Dim ftp As Net.FtpWebRequest = GetRequest(url)

'Set request to do simple list

ftp.Method = Net.WebRequestMethods.Ftp.ListDirectoryDetails
Dim response As FtpWebResponse = ftp.GetResponse()
Dim sr As New StreamReader(response.GetResponseStream())
Dim str As String = sr.ReadToEnd()
'replace CRLF to CR, remove last instance
str = str.Replace(vbCrLf, vbCr).TrimEnd(Chr(13))
'split the string into a list
If Not Authenticated Then
Authenticated = True
RaiseEvent StatusChanged(response.WelcomeMessage)
RaiseEvent StatusChanged("Login successful...")
End If
RaiseEvent StatusChanged("Current directory is " & CurrentDirectory)
Return New FtpDirectory(str, url)
Exit Function
em:
MessageBox.Show(Err.Description)
End Function


The regular expressions are matched based on six different unix directory listing patterns that are most commonly used.



Public Enum DirectoryEntryTypes
File
Directory
End Enum

Sub New(ByVal line As String, ByVal path As String)
'parse line
Dim m As Match = GetMatchingRegex(line)
If m Is Nothing Then
'failed
Throw New ApplicationException("Unable to parse line: " & line)
Else
Me.FileName = m.Groups("name").Value
Me.Path = path
Me.Size = CLng(m.Groups("size").Value)
Me.Permission = m.Groups("permission").Value
Dim _dir As String = m.Groups("dir").Value
If (_dir <> "" And _dir <> "-") Then
Me.FileType = DirectoryEntryTypes.Directory
Else
Me.FileType = DirectoryEntryTypes.File
End If

Try
Me.FileDateTime = Date.Parse(m.Groups("timestamp").Value)
Catch ex As Exception
Me.FileDateTime = Nothing
End Try
End If
End Sub




Private Function GetMatchingRegex(ByVal line As String) As Match
Dim formats As String() = { _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})(\s+)(?<size>(\d+))(\s+)(?<ctbit>(\w+\s\w+))(\s+)(?<size2>(\d+))\s+(?<timestamp>\w+\s+\d+\s+\d{2}:\d{2})\s+(?<name>.+)", _
                    "(?<timestamp>\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?<dir>\<\w+\>){0,1}(?<size>\d+){0,1}\s+(?<name>.+)"}Dim rx As Regex, m As Match
For i As Integer = 0 To formats.Length - 1
rx = New Regex(formats(i)) 
m = rx.Match(line) 
If m.Success Then 
Return m 
End If 
Next 
End Function
























For connecting to the remote ftp server, we use the FtpWebRequest class provided by the .NET framework class library through the System.Net namespace. The StatusChange() event of the FtpClient is used to get notifications in the main form where we can display or log this status on a multi-line text-box.

Private Sub client_StatusChanged(ByVal newStatus As String) Handles client.StatusChanged
txtLog.AppendText(newStatus &amp; Environment.NewLine)
Application.DoEvents()
End Sub

The client object's ListDirectory() function is again called when the list view item is double-clicked or an upload is complete

Private Sub ListRemoteDirectory(ByVal directory As String)
lvwRemote.Items.Clear()
'Request = CType(FtpWebRequest.Create(txtUrl.Text), FtpWebRequest)
'Request.Credentials = New NetworkCredential(cred(0), cred(1))
RemoteDir = client.ListDirectory(directory)
LastDirectory = directory
lvwRemote.Items.Add("..", "..")
For Each item As FtpFileInfo In RemoteDir
If item.FileType = FtpFileInfo.DirectoryEntryTypes.Directory Then
lvwRemote.Items.Add(item.FileName, Images.CLOSED_FOLDER)
Else
lvwRemote.Items.Add(item.FileName, Images.FILE)
End If
Next

End Sub

Private Sub lvwRemote_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles lvwRemote.DoubleClick
If lvwRemote.SelectedItems.Count = 0 Then
Dim item As ListViewItem = lvwRemote.SelectedItems(0)
If item.ImageIndex = Images.FILE Then
ListRemoteDirectory(item.Text)
End If
End If
End Sub

The remaining tricks of the trade can be easily understood once you go through the code. For any doubts or queries please contact me. 

..............................................................................................
EDIT: As of today (22-07-2012), I've re-created this project with the following improvements:

1. I've realized that the complexity involved in implementing the FTPWebRequest, deserves a modular approach. Hence, I've developed the FTP library as a class component (DLL) separate from the GUI component. This way, the library can be reused without the burden or overhead of a WinForm.

2. Multi-threading: .NET can certainly leverage the multi-threading capabilities of the newer dual-core processors. I've hence implemented multi-threading by running uploads/downloads on separate threadeds.

3. Event-based: I've included some more events such as uploadCompleted and downloadCompleted to facilitate the end-users of the library.

4. Finally, I've developed the newer version in the C# language, as I'm more used to it in recent years.

You can find the newer version in the codeplex repository here.

The update tutorial for C# is here.