Laptop Backup is an idea that has been sitting on the back burner for some time now. I had the intention to write it but never got around to it until I had a bad month and had to rebuild all my computers for one reason or another. Not only did I lose work but emails and software that I'd purchased as downloads and quite a few e-books that I no longer have the rights to read. Not to mention a level twelve ambidextrous thief in Never Winter Nights. Action was called for and this is it.
Originally it was intended to maintain the data between the main computer and the laptop (hence the name) but my laptop decided it was fed up with all this computing nonsense and decided to realize its true vocation as a large expensive paper weight. Since then I have used this program to collect all the files that I want to back up into one folder so that when it is time to do the monthly backup I don't have to go searching round the hard disk trying to remember where everything is. This does unfortunately mean that if anyone has problems with the remoting setup side of things, you have the source code and you're on your own.
There is, as well as this document, a user guide contained within the Zip file. This includes basic setup stuff and a couple of small walkthroughs for how to use the program.
The program was designed to work in two parts. The first part being the GUI and the second part being the service. The program is designed to work cooperatively; that is, you cannot install it on one machine and expect it to back up files to another machine. This idea seemed a little simplistic to me and meant that I wasn't able to achieve the kind of program operation that I was looking for. I didn't feel that that mode of doing it was right, and what if the computer you're trying to back up files to is turned off. There is no back up then, so I had to allow options that would enable retrying until done without constantly backing up the same files all day or not backing them up at all if the computer the files were on is turned off. I'll get back to the cooperative bit and explain what I mean by that sentence in a minute.
The idea behind the design was that I wanted to set up a back up system that would allow people to use it without taxing their little brain cells. This meant that there could be no messing about with TCP connections and sockets and getting the user to set it all up. It had to run straight out of the setup program. And with a reboot or starting the service manually, it should. The checking that the connection works should also be simple and in the case of the GUI it requires a simple click on the validate button before the program allows you to access the remote computer. This is simply a check to see if it can connect to the other computer.
So what do I mean by a cooperative program? Well, it goes like this. As I mentioned earlier, the program does not work the way you would expect it to work. The first and the most important difference to get your head around is that the program does not copy files from the computer it's running on to another. It gets them. What you do when you set up a file to be copied by the service is set the files details in the registry so that at the required time, the service will check that the computer is up and running as part of the network, and then it will get the file from the other computer. The service will under no circumstance copy a file from its own hard drive to another computer. Well, not unless you rewrite the source code to do it.
The way this works is that the Laptop Communications DLL runs as a proxy object; which is to say that if you are running the code from your main computer to copy files from your laptop, then the Laptop Communications DLL will actually be running on the laptop, even though all the calls to it are running through the code on the main computer. This is done through the remoting technology built into the .NET Framework which I'll give more details about later.
There is one concession I have made and that is in the port number. Although I have set it to a default which works fine on my system, I suspect that there are going to be a number of people with firewalls that want that port blocked. I added the ability to change the port value as a concession to people with firewalls.
Another main thing that bothered me in the original thinking about the program was the sharing of folders. If I wanted a program that could go between computers easily without confusing the barely computer literate, I had to find a way to get around the sharing of folders. In fact, I had to get around the idea that the program was doing anything technical or special at all. To the end user, it should appear as if they were selecting the files or folders that they wished to back up. That was as complicated as it was allowed to get, as far as the end user is concerned. With this in mind, the user interface was designed so that to the end user it appears that they are using an Explorer-type dialog to browse the hard disk. The fact that it is the hard disk of a computer other than the one that they are currently sitting at should be of no concern to them. Indeed, the only time I make the end user aware that there is another computer involved in the entire process is during the setup of a new computer to the program, and when the user interface starts, it asks them to validate the remote computer. The validate function just checks that the communications channel can be established with the remote computer.
So it's all well and good having a program that backs up your files, but why write one? And what's the difference between this and all the other programs out there? Well at the outset, the program was designed for personal use--not for business use. This means that it is meant for copying my saved game directories, programming folders, and personal documents between computers, meaning that for me to lose all my work, all the computers using the back up program would have to explode simultaneously.
The program does the job it was intended to do and for this reason it doesn't write to tape drives or burn CDs although there is nothing stopping people from copying all their files to the same subdirectory and burning the CD themselves. Nor is it designed to back up an entire computer. In its present version, the program would not successfully be able to back up an entire laptop hard drive and copy it back into the laptop at a later date, due to the problem of accessing files that are currently being used by the operating system. This is a function I have no intention of adding because it is not what I needed the program to do. If anyone wants the program to be able to do that then they have the source code provided. At this moment in time, I'm far too busy pretending that the fact that I finished Never Winter Nights before I finished the back up program doesn't bother me.
The interface for Laptop Backup was designed so that it is possible to use as many computers as you like to organise your files. Of course, as I had no idea how many computers there was going to be, I had to devise a way to set up the interface so that it could cope with any number of additions. There were two ways to do this. One was to write a function that would redraw the layout for each tab. The other was to inherit from the tab page class and then instantiate that class repeatedly. This allowed me to use the designer to develop the interface and then simply copy the setup code into the
BackUpTab class constructor. This means that there is no code-defined limit to the number of computers you can have running the back up program.
The main screen for the Laptop Backup program is pictured above. The main display panel contains the functionality to add and delete computers. It should be noted that any edits made on the tab pages are saved automatically so the Save And Exit button only really saves the computer changes. The tab pages contain all the computer specific information, such as the name that you choose to call the computer, and the IP address, which in the display is localhost for the current computer. The Validate button checks that the computer connection is working alright, and the Add New, Edit and Delete buttons are for controlling the details for the individual lists. All of this is discussed in the Laptop Backup User Guide, included in the Zip file. For this reason I'll only skim over the basics of the interface in this section.
Basically, all the details for the program are stored in the registry where they are picked up by the service, so the purpose of the user interface is to do nothing more than to collect the data required. This is mainly done through the Add New button, with the Edit button allowing you the facility to fine tune your settings once you have set them up. For instance, during testing I discovered that the save games for Divine Divinity were clocking up around 300 meg. Until this point I'd assumed that the programming files were going to be the largest amount of data that I would be copying. 300 meg is no small amount of data and takes a while as well, so once I knew this I changed the settings for this directory to only do the copy every seven days.
The Add New button is the primary set up and as above is discussed more thoroughly in the User Guide included in the Zip file.
The Add New dialog implements the design mentioned above in that it displays the drive data in a standard Explorer type interface. On the whole it feels a little clunky in use and doesn't respond to the mouse as quickly as I'd consider ideal. The focus on the buttons work downwards so that you can't set the destination of the file before setting the file and you can't save the data before setting both the Add and the Destination. This seemed much cleaner than trying to keep track of what was going on as people randomly selected buttons to see what they did.
The service, called
BackUpService is the main workhorse of application that it is responsible for working out which files are required to be copied every time that the timer fires. It does this by quite simply reading the registry items that the user interface program created. While there, it also adds a couple of registry values to each entry in the registry that it uses for its own book keeping. The primary key that it adds is the "Done" value. This is added so that when the user interface has set the try until done variable in the registry, the service has a quick and easy way to work out if it has already finished copying the current item. The "Done" value prevents the service from having to go through all the files every single time the timer fires as this is impractical and time consuming.
One of the primary functions in the service itself is the
CheckRegistryKeys function. This is called at various times throughout the running of the service and is responsible for the control of the program. At the start of the program, it sets the all the registry keys for the program's "Done" value to false and updates the current check date to the current date. At the end, it maintains the
DaysTilCheck value, decreasing it if necessary.
The main functionality provided by the service is in the
OnBackupTimerTick function that deals with the actual copying of the files. It should be understood that there is no limit on the size of the files that you can copy so the function implements a working variable which means that if it is busy it will do one task at a time, before moving on to the next. I felt this was reasonable given that the program is designed to back up purely personal data rather than being aimed at large corporate systems, so speed of copying wasn't as important as getting it right.
How The Program Uses Remoting
Both the user interface and the service rely on the remoting services provided by the Microsoft .NET framework. This is a system that allows computer programs to talk to other computer programs on another remote computer, hence the name remoting. The .NET framework provides a much-simplified mechanism when compared to earlier attempts such as DCOM, which required a deal of specialised knowledge about exactly what was going on, and was something that many otherwise-intelligent programmers completely failed to grasp.
Both the user interface and the service start by setting up what is called a listener. This is a piece of software that listens for incoming calls from remote computers. It should be noted here that the listeners set up within the program are not listening specifically for inputs from any specific computer but to inputs coming in at a certain location. The code that the user interface uses to set up the listener is:
listenChannel = new TcpChannel( 0 );
ChannelServices.RegisterChannel( listenChannel );
listenChannel is declared as a
TcpChannel that is created with a 0 parameter which is important because when a
TcpChannel is created you can specify the port that the channel will listen on, but the theory goes that if you specify a zero in the
TcpChannel constructor then the channel can listen on any available port. This however, doesn't apply when it comes to services. If, as an experiment, you set the
TcpChannel to 0, it will constantly complain that the connection has been refused. This is only fixed when you explicitly add the port number. This brings us to one slight draw back in the remoting framework that I suppose is a matter of opinion if it is a serious drawback or not, but if you have a service listening on say, port 8086, that works for laptop backup, then you cannot specify that the user interface controlling the service listens on the same port. The error given states that only one item can listen on the port. If you try setting the user interface to listen on port 8086, an error is reported saying it already being used. The way to get around this is to specify 0 in the
TcpChannel for the user interface and the proper port number for the service.
Once the port that the
TcpChannel is to listen on has been decided, register the channel with the .NET Framework using the
ChannelServices.RegisterChannel function and then register the service type. The service type is a remotable object which, in this case, is the
CommunicationChannel object, which inherits from
System.MarshalByRefObject. The communications channel handles the remoting references for both the user interface and the service and is registered with the system by calling
RemotingConfiguration.RegisterWellKnownServiceType. This does not instantiate a proxy to the object on the remote computer, it simply registers it with the current computer. The registered object is given a URI or a name that can be used by the system to find the object and a call type which can be either Singleton or SingleCall. A Singleton object will be kept valid throughout the scope or lifetime of the program, whereas a SingleCall type will create a new instance of the proxy with every call to instantiate the object.
One thing that I did come across in testing the application is that there seems to be a finite number of connections that can be made. Every so often when backing up large numbers of files, the code flags an error that there is no receiver registered. This was partly my fault in that I had a class object that was repeatedly calling the activator function and wasn't allowing the objects to go out of scope which meant (I suspect) that the garbage collector (understandably) wasn't releasing resources because it wasn't told they should be released. This error was fixed by making the communications channel object local to the functions that require it which gives the garbage collector a fighting chance to clean up after me.
An instance of an object is only created when the code calls:
communicationsChannel = (CommunicationChannel)
which instantiates the connection to the object on the remote machine. Well almost, at this point you can still find that the object is invalid, what appears to happen is that this instantiates the proxy on the local machine. For this reason, you need to be careful when first using the object that you believe to have already been instantiated, as the first time you use it you could get a
SocketException that says that the code is not available because the remote machine has actively refused it.
GetObject function takes two parameters, these being the type of the proxy object that you are creating and the string for the URL. In the case of the Laptop Backup program, this will read something like "tcp://localhost:8086/LaptopBackup" which breaks down to "tcp", the protocol to use, "localhost", the IP address of the computer that you want to connect to, in this case the local host or current computer that Laptop Backup is running from. This will normally be a number like 126.96.36.199. The "8086" indicates the port number that the code is running on and the "LaptopBackup" is the name or URI of the program.
- Install on all target machines.
- Restart the computer or start the service directly.
- Add computer that you wish to get files from to the main program.
- If necessary, type ipconfig at the command prompt to get the IP address.
- If connection is still not working and typing ping at the command prompt works, then set the executables for the program in your firewall exemption list.
- Set up the files that you wish to back up. If unsure, consult the user guide walkthroughs provided with the source code.
The program is currently tested across two computers and three hard disks running Windows XP Home and Professional, copying about a gig of data and around 7000 files and is run on one computer in debug mode and on the other in release mode.
- 10 March 2004:- Initial release.
- 14 March 2004:- Fixed 1 level directory bug, fixed refresh bug.
- 27 July 2004:- Handled the cancel options correctly for the dialogs.
- 6 June 2005
- Rewrote file handling.
- Fixed dropping out of loop when a single file fails.
- Fixed Checked Directory copy getting confused at the end of a directory tree.
- Cleaned up walkthrough so images display properly.
- Tom Archer (2001) Inside C#, Microsoft Press.
- Charles Peltzold (2002) Programming Microsoft Windows With C#, Microsoft Press.
- Robinson et al (2001) Professional C#, Wrox.