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

Directory Mirroring the way it should work

4.89/5 (12 votes)
9 Jun 2009CPOL26 min read 49.3K   1.9K  
Create useful directory restore points, quickly and easily.

Image 1

Contents

Introduction

DirMirror creates and maintains an exact copy of a source directory in a target directory, creating and maintaining "Restore Points" for directories you choose. The files and directories in the target directory will have the exact dates and supported attributes as in the source directory. The mirror process will only copy those directories and files that are different from those in the source. Files and directories in the target that do not exist in the source will be deleted. The "exactness" of the mirror may be modified to exclude and/or ignore directories and files to protect items in the target that should not be changed or deleted, and to reduce copy time and space used in the target. DirMirror works for all locally connected directories (hard drives, USB keys, mapped drives, network shares, etc.) that use either the NTFS or FAT32 file systems. I have tested it on old USB keys that claim to use the FAT file system, but, I do not claim that it will work on real FAT file systems. DirMirror does not support FTP. To use DirMirror, you must have the appropriate permissions according to the rules of the systems it is running on or accessing.

Background

In addition to normal backups, I like to keep an exact copy of specific directories on another disk. This copy can be thought of as a restore point for a directory. It is particularly useful for answering the question "What Changed". I also use this technique for coordinating active directories between Desktop/Laptop/Other System situations. For several years, I used SyncToy version 1.4 running in "Echo" mode for this purpose. Recently, I tried SyncToy 2.0. It was a disaster in the "Echo" mode. Furthermore, while running down the various problems, I noticed that version 1.4 was less than perfect, though its problems are more subtle and less significant.

Since I wished to have the mirror capability, and did not wish to deal with finding and testing some other replacement package, I asked the question "how hard can it be to write my own?". As it turned out, the answer is "as hard as you want to make it". For those who just want to use the package, all the code details are found in the How DirMirror Works section and may be skipped. For my expected audience, the details are the interesting part.

Compared to Vista's Sync Center

  • Easy one-way sync from source to target on the same computer
  • Runs on XP as well as Vista
  • Source and/or target may be on network folders - unlike Vista Home... systems
  • Does not require a service or other long running background process
  • Has no catalog or database to get out of touch with reality
  • You control when and how it runs
  • No claim to work with cell phones, MP3 players, etc.

Disclaimer

DirMirror is not a backup solution. For backups, use a package that claims to be for that purpose. DirMirror is a way to create and maintain a restore point for a directory, easy to use, as quick as the hardware (and Windows) will allow, and as reliable as I can make it at this time, with the hardware I have available to test with. I would not use someone else's software for something like this without testing it out myself. I do not expect CodeProject members to skip the testing phase any more than I would.

DirMirror is not a synchronizing solution. For synchronization, use a package that claims to be for that purpose. DirMirror makes the target directory look exactly like the source directory. If you have made changes in both the source and target, you will lose the changes you have made to the target unless you explicitly Ignore those changed directories and files in the Target. Of course, you may define folder-pairs such that the source and target are reversed, and use them for synchronizing, retaining complete control of what gets "synched" and when. In many situations (one person, two computers, for example), this is a preferable method for those who like to retain control of their own data. For more opinion, see My Definition of Backup, Synchronize, and Mirror, later in this article.

Definition of Terms used in this Article

Throughout the article and the code, files are represented by FileItems. Directories are represented by DirectoryItems. The term Item is used to refer to an instance of either.

Throughout the article and the code, the term Key refers to that portion of an Item's path with the path of the source or target stripped off. This stripping leaves the terminal Path.DirectorySeparatorChar as the first character of the Key. For example: given a source directory of "C:\Test", the Key of the directory "C:\Test\Junk" is "\Junk" and the Key of "C:\Test" is "\". This definition is vital to understanding the code and the concept of pattern matching as applied to directories.

Using DirMirror

Each user of the application has an instance of a list of FolderPairs. Each FolderPair item designates a source directory and a target directory. Each FolderPair also contains Options, IgnoreLists, and ExcludeLists. These lists allow the user to ignore and/or exclude certain files and directories from the Delete and Copy operations.

DirMirror comes with an interactive GUI version (DirMirror.exe) and a command line version (DirMirror.com). The command line version is discussed later. The GUI version must be used to define pairs of source and target directories and to set any options for a FolderPair. Once a FolderPair has been defined and configured, it remains available for use by all future DirMirror executions until it is explicitly deleted.

To use DirMirror:

  1. Start DirMirror.
  2. If needed, create the desired FolderPairs by clicking on "Create New FolderPair". Use the default options for a pure mirror, or change them as desired.
  3. Click on a FolderPair name in the left pane of the GUI. This will change the display and run a preview.
  4. Click on the "Details" button to see another view of the pending operations and, if desired, cancel an operation on selected directories and files (optional step).
  5. Click on the Execute button to start the mirror operation.
  6. Observe what happened (optional step).
  7. Repeat as needed.
  8. Exit DirMirror.

Usage Notes

Text in the GUI is displayed in two shades of blue. Text in the darker shade may be clicked on to cause something to happen. Certain such areas respond to both right and left clicks, but some only respond to a left click. For example, a left click on a FolderPair name will start the scans of the source and the target and display the Preview/Action page for that FolderPair. A right click on a FolderPair name will allow you to change the options for that pair, or to delete the FolderPair (just the entry in DirMirror's lists, not the actual directories), to rename a pair, or to see the options for the pair in a more convenient view. Any click on a dark blue number in the listview will show the directories or files that fall into that category (directories to delete, for example). Any click within the Options settings groupbox will display a propertygrid allowing you to change any option for that pair.

The Demo_ReadMe.htm provided with the demo download provides a GlobalFileIgnore list that matches the files that normally have meaning only in the context of their original directory. You may consider using that list for all of your FolderPairss.

Certain uncommon types of files may cause errors and be skipped when copying from an NTFS file system to a remote or non-NTFS file system. I have not tested DirMirror on sparse files or on files with reparse points. If you have such files and can test DirMirror on them, please do and let me know the results.

Encrypted and Compressed Directories and Files

Files and directories that are encrypted or compressed by NTFS do not travel well. These restrictions only apply to NTFS encryption/compression, not encryption/compression done by another method (WinZip, etc). This version of DirMirror will retain the encrypted nature of a file when copied to a target located on a fixed drive NTFS volume on the same system as the source. It will also retain the "Encrypted" attribute on directories when that directory is copied to a target located on a fixed drive NTFS volume on the same system. To avoid exposing their encrypted content, encrypted files will not be copied to anything other than a fixed drive NTFS volume on the same system.

Compressed Items copied by DirMirror will remain compressed when copied to a fixed drive NTFS volume. Compressed directories will retain the "Compressed" attribute when copied to a fixed drive NTFS volume. Compressed Items copied to any volume that is not a fixed drive NTFS volume will be copied as decompressed, and will not retain the Compressed attribute.

Options, Exclude Lists, and Ignore Lists

The first thing to know about Options and Lists is that you should have a good reason for using them. The second thing to know is that you must read and understand this section. It is possible to get strange and unexpected results if you do not understand the interactions between the Options and Lists and if you do not fully grasp how the Lists work. Of course, you may use a "pure" mirror with no Exclude or Ignore lists and therefore not need any of the following information.

Options

Overwrite How to handle the overwrite of a newer file in the target. The choices are "Ask", "Never", and "Always" with the obvious meanings.
DeleteExcludesHow to handle a file or directory in the target that has a match in an ExcludeList. True means delete it, False means do not delete it.
UseGlobalExcludeTrue to use the Global ExcludeLists as well as the FolderPair unique ExcludeLists.
UseGlobalIgnoreTrue to use the Global IgnoreLists as well as the FolderPair unique IgnoreLists.

Exclude and Ignore Lists

The Ignore and Exclude lists are lists of directories and files that you want to be treated in special ways. The lists may contain wildcard characters. Items that match a pattern given in a list will be "Ignored" or "Excluded". There are four global lists (DirIgnore, DirExclude, FileIgnore, and FileExclude) and four FolderPair specific lists. The Global lists are associated with a user of the application, and the FolderPair specific lists are unique to a specific FolderPair. A FolderPair may be configured to use all, some, or none of the lists.

Wildcard Characters and Pattern matching

DirMirror uses the VB.NET Like operator to perform matching. A "*" character will match zero or more occurrences of any character. A "?" character will match any single character. See the documentation for the Like operator for additional pattern matching capabilities. Unlike the Like operator, all Ignore/Exclude comparisons in DirMirror are case-insensitive.

When matching an Item against a List, files and directories are treated differently. For files, the List pattern is matched against the file name, including the extension. Thus, to Exclude all .pdb files, the match pattern is "*.pdb".

Directories are matched against the Key with a Path.DirectorySeparatorChar ("\") appended. Thus, to Ignore a directory named "MyLocalApp\bin", the match pattern is "*\Mylocalapp\bin\*" (note the trailing "\*" and that case does not matter). A pattern of "*\MyLocalApp\bin*" will also match "mylocalapp\binary", which is probably not what was intended.

Because of the nature of directory matching, the application will always modify any directory match pattern to have a leading "*". If you enter a directory match as "\obj\*", it will be transformed, at entry, into "*\obj\*".

Ignore Lists

A file or directory that matches an entry in an IgnoreList will be ignored for all purposes during processing. It will not be copied from the source, and it will not be deleted from the target. It will be preserved in the target even if it falls below a directory that is otherwise to be deleted. In this case, all necessary directories in the full path of the ignored Item will be preserved, though their non-ignored content will be deleted.

Exclude Lists

A file or directory that matches an entry in an ExcludeList will not be copied from the Source to the Target. If the DeleteExcludes option is True for a FolderPair, any item in the target that matches an entry in an ExcludeList will be deleted. The only exception to this rule occurs when an excluded directory contains one or more Ignored Items. See Ignore Lists for details.

Interpreting the Preview and Done Counts

Directories that are to be (or were) copied, deleted, ignored, and excluded are counted as a unit. Files and sub-directories under such a directory are not counted separately. If the only action of a mirror is to copy a single directory, the only count will be 1 for that directory. The total lengths of all files under that directory will be reported under the "Bytes" heading.

If a FolderPair uses Ignore and/or Exclude lists, you may observe multiple files and directories reported to be (or were) separately counted that you did not expect to see. If the Ignore and/or Exclude lists prevent treating a directory as a single entity, the individual actions are reported. Obviously, if a mirror only needs to overwrite two files and to copy three other files, you would see them counted as 2 to overwrite and 3 to copy.

A special case occurs when DeleteExcludes is True; a directory matches an ExcludeList, and an Item that matches an IgnoreList falls under that excluded directory. In that case, all directories under the excluded directory that are in the path of the ignored Item are retained, but their (non-Ignored) content is listed as to be (or were) deleted. Such content will be displayed separately in the Preview display. A similar situation can occur when a directory that would otherwise be copied as a unit contains excluded Items. For the source directory, Exclude and Ignore matches are both treated as excluded Items.

Items in the source that match an Ignore pattern are listed as Excluded, therefore you may see "Excluded" counts when you had no ExcludeLists at all. If there are Items that match Ignore patterns in both the source and the target, you will see counts for each, as "Excluded" for the source, and "Ignored" for the target.

Learning to Trust the Application and Yourself

I certainly would not make use of an application like this without trying it out. I would also play with the Options, Ignore and Exclude lists to see how they work for me. As part of developing the application, I built in a variety of ways to check how it was working. Most of the features and tools that I used are still available, and I encourage you to use them.

Clicking on any non-zero count in the ListView on the Preview/Action display will show a list of the Items included in the count. Click on the "Details" button to see a separate window displaying the full list of Items that have pending actions to be taken. A click on any non-zero count in either ListView will show the list of Items included in the count. Any action may be cancelled, for this run only, by double clicking on the Item in the Details display. Another double click on the same Item will restore the cancelled action.

Once "Preview" has been done for a FolderPair, you may click on Tools-->Show Trees to generate and display a rather crude ASCII tree of both the source and target directories showing the actions to be done and how they fit in the directory structure.

You may click on Tools-->Log Options to view the current log and all the available previous logs. You may also change the logging options on this window.

Testing DirMirror

For those who do not wish to risk their own data while playing with DirMirror, the demo download provides test directories and supplemental information. Immediately beneath the demo directory is the Demo_ReadMe.htm file which describes how to produce the results shown in the image at the top of this article. There are also several .txt files which provide detailed reports of the results of running the tests. Beneath the demo directory are three sub-directories, TestSource, TestTarget, and CopyOfTestTarget. Use TestSource as the source, TestTarget as the target, and CopyOfTestTarget to refill the target to make additional trials. The contents of these directories is meaningless, but has a variety of Items that will give the options and lists a good workout. The content also includes a number of files with a good selection of the attributes of interest to DirMirror (ReadOnly, Hidden, System, Compressed, and Encrypted). Note again that Vista Home ... systems do not support encryption.

From the Command Line

The command line version, DirMirror.com, accepts a list of one or more FolderPairs and executes the mirror operation specified by each pair. Pairs cannot be defined or modified by the command line version, they must be set up using the GUI version. For more information, type "DirMirror /?" at the command prompt while in the same directory as DirMirror.com.

How DirMirror Works -- The Details

Data Structures and Major Classes

As described above and repeated here for emphasis, the most significant data element throughout the article and the code is the Key. The Key consists of the full path of a directory or file, with the full path of the source or target directory stripped off, leaving the leading "\". For example: given a source directory of "C:\Test", the Key of the directory "C:\Test\Junk" is "\Junk" and the Key of "C:\Test" is "\".

Unlike Windows Item names, Keys are case sensitive. The Keys of "\Junk\a.txt" and "\Junk\A.txt" are considered to represent different file names. The concept here is that if you changed the casing of an Item name in the source, you will want that change reflected in the target.

The most important data structure used in DirMirror is Dictionary(Of String,Item). During processing, multiple such dictionaries are created, modified, and processed. This article uses the term Dictionary to represent such data structures. In all cases, the key of such a dictionary is a Key as defined above.

Major Classes
ClassFunction
FolderPairContains all information defining a source and target pair. This includes all pair specific Ignore and Exclude lists and all options for this pair.
FolderPairsContains the user specific list of FolderPairs. Provides the methods to Serialize (save) and Deserialize (load) this list. Also contains the Global Ignore and Exclude Lists.
DirListRepresents a source or target directory. Creates and wraps a dictionary containing all sub-directories of the directory that this instance represents. Contains the method (DirList.GetInfo) to gather the information for all Items contained in this instance, building a tree-like structure of the directory. Also contains the method that is used to build Keys.
ItemWraps a W32_FIND_DATA structure, exposing certain application specific methods and properties.
DirectoryItemInherits from Item. Contains all Items of sub-directories and files contained in this instance. Exposes certain directory and application specific methods and properties.
FileItemInherits from Item. Exposes certain file and application specific methods and properties.
AnalysisContains the methods to analyze a FolderPair to determine which actions need to be taken to mirror the source onto the target. The results of running an analysis are what is displayed to provide a preview of the mirror operation prior to running the mirror.
DoOperationsPerforms the Copy, Delete, and Overwrite operations needed to build the mirror.
WinApiContains the P/Invoke declarations of the various APIs used by DirMirror.
LoggerProvides the methods necessary to create a LogFile and to write to it. DirMirror logs all of its directory and file operations as well as some information about intermediate processing steps.

The Item, DirectoryItem, and FileItem classes are roughly analogous to the .NET FileSystemInfo, DirectoryInfo, and FileInfo classes. I do not use the .NET classes for several reasons, primarily speed.

The Basic Analysis Algorithm

The Analysis (Preview) phase is the most complex part of DirMirror. It is the handling of the options, and the Ignore and Exclude lists that makes it so. However, the basic (ignoring the options and lists) algorithm is fairly simple. The actual code is more complex since it does have to deal with options and lists. The simple version could be coded as follows:

VB
'Given a Dictionary of all Source Directories (SrcDict)
'  and a Dictionary of all Target Directories (TgtDict)
'  and an empty Dictionary of Directories that have equal keys (DirsUnchanged)
'  and an empty Dictionary of Directories that should be Copied (DirsToCopy)
    Dim SrcKeys(SrcDict.Keys.Count - 1) As String
    SrcDict.Keys.CopyTo(SrcKeys, 0)
    Array.Sort(SrcKeys, New DirNameComparer)
    Dim SrcIndex As Integer = 0
    Do While SrcIndex < SrcKeys.Length
        Dim SrcKey As String = SrcKeys(SrcIndex)
        Dim SrcItem As DirectoryItem = SrcDir(SrcKey)
        If TgtDict.ContainsKey(SrcKey) Then
            DirsUnchanged.Add(SrcKey, TgtDict(SrcKey))
            TgtDict.Remove(SrcKey)
            SrcIndex += 1
        Else
            DirsToCopy.Add(SrcKey,SrcItem)
            SrcIndex += 1
            Do While SrcIndex < SrcKeys.Length AndAlso _
                     SrcKeys(SrcIndex).StartsWith(SrcKey)
                SrcDict.Remove(SrcKeys(srcIndex))
                SrcIndex += 1
            Loop
        End If
    Loop
' At this point, any Directories left in TgtDict are scheduled to be Deleted

The code would then examine each file in each directory in the DirsUnchanged Dictionary in a similar fashion, putting the files to be deleted and copied into similarly named Dictionarys. Files that are "Equal" are simply ignored for further processing.

When are Two Files Equal?

Two files are considered equal if their Keys match and if they pass the following function's equality test:

VB
Private Shared Function FilesEqual(ByVal SrcFi As FileItem, _
                      ByVal TgtFi As FileItem) As FileResult
'We assume that the file names are equal, else we would not be calling this
  FilesEqual = FileResult.NotEqual            'assume not equal
  Dim TimeEqual As Boolean
  If SrcDir.IsNTFS AndAlso TgtDir.IsNTFS Then
      TimeEqual = SrcFi.LastWriteTimeUTC = TgtFi.LastWriteTimeUTC
  Else
      TimeEqual = DateDiff(DateInterval.Second, SrcFi.LastWriteTimeUTC, _
                  TgtFi.LastWriteTimeUTC) <= 2
  End If
  If TimeEqual AndAlso SrcFi.Length = TgtFi.Length AndAlso _
         AttrMatch(SrcFi, TgtFi) Then
      FilesEqual = FileResult.Equal
  ElseIf SrcFi.LastWriteTimeUTC < TgtFi.LastWriteTimeUTC Then
      FilesEqual = FileResult.Newer
  End If
End Function
Private Shared Function AttrMatch(ByVal F1 As FileItem, _
                         ByVal F2 As FileItem) As Boolean
  Static AttsToTest As FileAttributes = FileAttributes.Encrypted Or _
                                        FileAttributes.Hidden Or _
                                        FileAttributes.ReadOnly Or _
                                        FileAttributes.System
  Dim Comb As FileAttributes = F1.Attributes Xor F2.Attributes
  If Comb = 0 Then Return True
  Comb = Comb And AttsToTest
  If Comb <> 0 Then Return False
  Return True
End Function

For two files to be considered equal, they must have identical LastWriteTimeUTCs snd must have identical lengths. They also must match in certain FileAttributes (ReadOnly, Hidden, System, and Encrypted). Note that FilesEqual also determines, for Not Equal Files, if TgtFile is newer than SrcFile. If so, that result is passed back to the caller, which deals with it based on the Overwrite option.

The question of LastWriteTimeUTCs equality must be based on which file system contains the FileItems. FAT and FAT32 file systems only keep LastWriteTime to an accuracy of 2 seconds. It is rare that a file copied from an NTFS volume to a FAT32 volume will retain the same LastWriteTime. The Windows Shell uses a similar 2 second window when comparing LastWriteTime, so my code is at least that good.

A further complication, not dealt with by DirMirror, is that FAT and FAT32 file systems do not actually keep LastWriteTimeUTC. Windows derives that value from LastWriteTime according to the Daylight Savings Time rules in force when the information is requested. This last point will result in the (unnecessary) Overwriting of many files, at Daylight Savings Time changes. I would like to fix this, but Windows XP and before does not keep historical information about Daylight Savings Time rules. In fact, I don't think Vista does either, though I haven't checked this out fully.

A Question of Speed

There are two time consuming phases of this or any similar application: doing the operations (Copy, Delete, etc.) and scanning the directories for current content. Actually, performing the operations is a fixed cost -- unless you can eliminate most of the copies, etc. -- which is what DirMirror accomplishes by only doing the minimum number of operations to bring the directories into a mirrored state. I assert (unproven) that some time is saved by copying directories, rather than individual sub-directories and files. Certainly it is true that not copying directories and files that are actually present and equal in both the source and target takes less time than copying them again (i.e., drag & drop in Win Explorer or an XCOPY script).

The initial scan of the source and target is not a fixed cost. Depending on what the media is, where it is located, the hardware it is running on, what else is running, and the size of the directories involved, dramatic time differences can occur. In unrelated efforts, I have determined that the .NET classes DirectoryInfo and FileInfo are quite fast for local disks. However, I discovered that those classes are painfully slow when scanning a network share, especially if the share is on a Vista system. Mapped directories perform about as well as locally mounted volumes, depending on the speed of the network.

For DirMirror, I use the FindFile and FindNextFile API calls. For a directory of any size on a Vista hosted network share, FindFile and FindNextFile do the scan in about 1/3 the time as the .NET classes. I think I know why this is, but haven't looked deeply enough at the question to speculate here. It is enough to know that the API calls are very much faster in that case, and are actually about 25% faster for local disks as well. Regardless of whether or not you use this application, the Item, DirectoryItem, and FileItem classes, and the supporting class WinAPI are useful in their own right in cases when speed is an issue.

DirMirror performs its directory scans on separate threads for the source and the target. Even on a multi-processor system across separate hardware, I am not sure that this gains significant time. I am sure that it allows me to change the GUI to display the Action/Preview panel while the scans progresses.

Over the course of this development, I became quite interested in where the time was going. As a result, I collected ElapsedTime information for various execution segments. This information is still being collected and may be looked at in the log files.

Should you accidentally click on a FolderPair that includes a network share that is unavailable, you will experience a long delay while Windows determines that the share is, in fact, unavailable. The delay is a function of your network timeout value and may be quite troubling. This delay is not a function of DirMirror and is not cancelable by DirMirror. Just wait, it will respond eventually.

My Definition of Backup, Synchronize, and Mirror

BackupA backup application is typically used to backup most or all of a system. Typically, it saves files and directories in a proprietary format and maintains multiple versions of files. Typically, it maintains a separate catalog of what it has backed up and where the versions are located. Everyone needs one of these to guard against catastrophic failure or virus infestations. However, it can be very time consuming to restore a file from a backup - as the app works through its catalog to present you with the choices available for restore.
SynchronizeA synchronize app is basically designed to merge two directories. It must deal with the possibility that changes have been made to both directories since the last sync. To accomplish this, it typically maintains a separate dataset for each directory, detailing the content of each. The first step in a sync is analyzing the current state of a directory against what the dataset documents. From that information, it decides what changes should be made to both directories to bring them in sync. A good understanding of the rules it uses to make that decision is important if you wish to avoid data loss. As with backup, a sync can spend a long time dealing with its own catalog.
MirrorAn app like DirMirror will never change the source. Changes to the target are made by comparing its current contents to the source. There is no possibility of a catalog being out of date or corrupted since there is no catalog involved. Files and directories in the target are directly available for examination or restoring back to the source with normal Windows methods. It is the user's responsibility to know when changes have been made to both the source and the target and to deal with how to merge them. Obviously, in this case, errors can happen, but it is the user making the error, not the software.

As the section header states, these are my definitions, not necessarily yours. There are hundreds, perhaps thousands of packages available for backup and synchronization. There aren't too many like DirMirror. When I first went looking for such an app, my first criteria was that I wanted one that would delete files and directories that no longer existed in my master source. I also wanted one that would allow me to exclude certain files that were large and of no use outside of the source, for example, .pch and .pdb files. Perhaps, I did not Google well, but the only one that seemed to meet my needs was SyncToy version 1.4. Then, Microsoft broke it with version 2.0. Once I really looked at "how" the breakage occurred, I discovered that 1.4 was not perfect. 1.4 leaves orphan directories in the target, and never changes the Creation Date of directories in the target to match those in the source. At that point, I decided to just write my own. Once I started, I got sufficiently carried away that the only way to justify the effort was to write this article.

Points of Interest

First off, the GUI of DirMirror looks a bit like SyncToy. I really liked version 1.4, and was used to its GUI (which is better than mine). Mine is a shameless imitation, but both SyncToy and DirMirror are free, so no harm done. Along the way, I learned a bit about ways one could build a GUI that looked like that. There are some interesting techniques in DirMirror that might be of interest to others whose strengths do not include messing with semi-dynamic GUIs.

For the few out there who are not experts in serialization, DirMirror provides worked examples of both Binary and XML based serialization. That same group may be interested in how to easily set up and use an application specific directory in LocalApplicationData. That is where both the FolderPair definitions and the log files live. Check out the modMain module.

Those who want to see a working example of using the PropertyGrid to change properties in your very own class, look at the PropertyEdit folder in this solution. This, along with the use of the <Editor(...)> attribute in FolderPairs and FolderPair also demonstrates the definition and use of your own UITypeEditor for working with List(Of String). This was based on a blog by Mohit Batra, a very nice piece of work.

DirMirror illustrates one way to build both a GUI and a CLI version in the same solution. I simply have two projects, one for the GUI and one for the CLI version, and set the IDE's "Start-Up" project to one or the other depending on which I wish to build. The CLI was a late add on, so the organization of the projects is less than optimal. It should be organized as three projects - a .dll with the main processing classes, and two executables, one for the GUI and one for the CLI. Instead, the GUI project contains all the code except for the "Main" module of the CLI version. This works, but causes the GUI exe to be loaded so that the CLI project has access to the main processing classes. Developers might note that the copy of the CLI executable is done as a Post Build step of the CLI project.

For those who only look at the code in an article, I include the following bit (taken from the HandleOptions.vb portion of the Analysis) to give some of the flavor:

VB
'Remove Ignored, Excluded, Deleted, and Retained items from the Local masters
Dim Lists() As Dictionary(Of String, Item) = {DirsIgnored, DirsExcluded, _
                                              DirsToDelete, DirsRetained}
For Each Lst As Dictionary(Of String, Item) In Lists
    For Each key As String In Lst.Keys
        SrcDict.Remove(key)
        TgtDict.Remove(key)
    Next
Next

History

  • 06/09/2009 -- Version 1.0 -- Original submission.

License

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