Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Remote File System Viewing and File Transfer using C# and TcpComm

5.00/5 (18 votes)
19 Sep 2019CPOL5 min read 75.6K   5K  
Learn how to view a remote machine's file system using your own explorer like window, and transfer files and folders by dragging and dropping in C# using the TcpComm TCP library

Introduction

This is a complete example of how to transfer files and folders over TCP, by using the explorer like window you see above in C#. Using the example application, you would transfer the files or folders by selecting them either in explorer and dragging them to the right pane in the transfer window, or selecting them in the transfer window's right pane and dragging them to an explorer window.

What we have here is very fast FTP like functionality, without the hassle most FTP clients normally come with. Instead of offering drag and drop functionality, many force you to deal with an antiquated feeling interface that has a separate window displaying the contents of the file systems of both the local and remote machine.

Using this example as a guide, you will be able to quickly build file and folder transfer functionality into your network application using the TcpComm library found here.

Even though I used the TcpComm library for this example project, you are not locked into it. I designed the RemoteFileSystem class (the class responsible for talking to the remote machine and getting file system information) to be a complete and separate entity, capable of being used with any network communications library. So if you have another network library you're more comfortable with, or would like to write your own, you will not have to tear TcpComm out of this project and force yours in, you can simply drop the RemoteFileSystem class into your project.

Background

I wrote and published the TcpComm library here on CodeProject in 2012. Over the years, people have asked me how to transfer folders. The library provides GetFile() and SendFile() functions in both the client and server classes... and I also provided a way to change the folder used by the client and server to receive incoming files. So when I was asked, most of the time I would just tell people that they needed to build folder transfer functionality into their application themselves. I would say that I had provided the tools, that the rest was up to you.

Recently, an application that I was working on required me to do exactly that - build a UI that showed the file system of a remote machine, and provide a way to transfer files between the local and remote machines. I wanted the interface to be fairly intuitive, so the clunky old Cute FTP style interface that had a separate window for each file system was out. I decided to build this functionality in a separate testbed application, and use the TcpComm library during testing so I could make sure the file transfer code in TcpComm was as tight as possible and also finally provide that example of how to transfer folders for people who have been asking over the years.

Using the Code

At the heart of this application, is the RemoteFileSystem class. It has its own client and server classes, and it is responsible for handling requests for information about the remote file system. The RemoteFileSystem.Server accepts requests in string form sent from the RemoteFileSystem.Client. The requests are formatted as XML, using an XML parser I built (XmlObject).

RFS (RemoteFileSystem) doesn't send any data over the network itself, it passes each request or response to your network communications library of choice via a delegate. In the example project, the code required to initialize the RFS server is very brief.

The RFS Server constructor looks like this:

C#
// Initialize RemoteFileSystem here:
rfsServer = new RemoteFileSystem.Server((String data) =>
{
    // Send data to the client here:
    UI(() => LblStatus.Text = "Sending data to client.");
    lat.SendArray(TcpComm.Utilities.StrToByteArray(data), 100, currentSessionId, ref errMsg);
}, (String newPath) =>
{
    // Handle requests to update the TcpComm server's received files folder here:
    var session = tcpServer.GetSession(currentSessionId);
    if (session != null) { session.ReceivedFilesFolder = newPath; }
});

By contrast, the client constructor is quite lengthy because the server's reply data is being parsed, and used to populate a Treeview and a ListView control:

C#
private void StartRFS()
        {
            rfsClient = new RemoteFileSystem.Client((String data) =>
            {
                // Requests are sent to the server here:
                String errMsg = "";
                if(!tcpClient.SendText(data, 100, ref errMsg))
                {
                    MessageBox.Show("Could not send data to the server!", 
                    "TCP Communications problem", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }, (RemoteFileSystem.Client.ServerReplyData serverData) =>
            {
                // Handle server replies here:
                if (serverData.type.Equals("getdrives"))
                {
                    // This code needs to be run on the UI thread:
                    UI(() =>
                    {
                        tvPaths.Nodes.Clear();
                        tvPaths.Nodes.Add("", remoteMachineName, 3);

                        TreeNode firstNode = tvPaths.Nodes[0];
...

This project is heavily commented. My intent was to have interested parties read through the example project so they can get a handle on how to use the different pieces of this puzzle.

Points of Interest

  1. When testing this project, if you decide to test the server on a separate network machine, make sure you start the server by right clicking it and running it as Administrator. If you don't, then the server application will not have access to the file system and will quietly close the first time you connect to it. 
  2. When you attempt to connect to the server running on a separate machine, make sure you specify the port in the connection string by separating the IP address or hostname with a colon, i.e.: your_IP_address_or_hostname:22490
  3. This example project contains a copy of XmlObject - an XML parser I wrote. It's built on top of XmlReader, so no - I wasn't trying to do anything groundbreaking. I just wanted to wrap the functionality that I was most likely to use, and make it usable in the way that I think we're all most comfortable with. For instance, when I look at XML, I see a collection of nested objects. So when I'm accessing the XML with my parser, I don't want to traverse nodes, or worry about illegal characters. I want to simply access my object, and get at its child objects easily like any other OO programmer.
  4. This project also contains a couple of helper classes. One is the CopyFile helper class. It does all the heavy lifting involved with transferring the files and displaying progress.
  5. The other is the DragDrop helper class. This offers the ability to get the name of the Windows Explorer folder the end user is dragging TO, because Windows doesn't offer that natively. Much of the code in this class was originally found here.

However, I have taken Mr Joy's example and completely rewritten it as a simple helper class, instead of a project spanning example. I have also refined it, so that you never see the dropped file, even if it's dropped onto the desktop.

Lastly, I have tested this application in Windows 7, Windows 10 and Windows Server 2012. In all of these OSs, it works properly. If you discover that it doesn't work properly in Windows 8, or Windows XP, please feel free to let me know below.

History

  • 2nd May, 2017: Initial version

License

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